/*=============================================================================
  D3DRenderRE.cpp : implementation of the Rendering RenderElements pipeline.
  Copyright 2001 Crytek Studios. All Rights Reserved.

  Revision history:
    * Created by Honich Andrey

=============================================================================*/

#include "StdAfx.h"
#include "DriverD3D.h"
#include "../Common/RendElements/Stars.h"
#include "I3DEngine.h"
#include "../Common/PostProcess/PostProcessUtils.h"
#include "CREParticle.h"





#pragma warning(disable: 4244)

//=======================================================================

bool CRESky::mfDraw(CShader *ef, SShaderPass *sfm)
{
  CD3D9Renderer *rd = gcpRendD3D;

#if !defined(_RELEASE)
	if(ef->m_eShaderType != eST_Sky)
	{
		CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Incorrect shader set for sky");
		return false;
	}
#endif

  if(!rd->m_RP.m_pShaderResources || !rd->m_RP.m_pShaderResources->m_pSky)
  {
    return false;
  }

  // pass 0 - skybox
	SSkyInfo *pSky = rd->m_RP.m_pShaderResources->m_pSky;
  if(!pSky->m_SkyBox[0])
    return false;

	float v(gEnv->p3DEngine->GetGlobalParameter(E3DPARAM_SKYBOX_MULTIPLIER));
  rd->SetMaterialColor(v, v, v, m_fAlpha);

	if(!sfm)
  {
    ef->FXSetTechnique(CCryNameTSCRC((uint32)0));
  }


  uint32 nPasses = 0;
  ef->FXBegin(&nPasses, FEF_DONTSETTEXTURES );
	//ef->FXBegin(&nPasses, 0 );
  if(!nPasses)
  {
    return false;
  }
	ef->FXBeginPass( 0 );

  rd->FX_PushVP();
	rd->m_NewViewport.fMinZ = 0.99f;
  rd->m_bViewportDirty = true;

  STexState pTexState;
  pTexState.SetFilterMode(FILTER_LINEAR);        
  pTexState.SetClampMode(1, 1, 1);

	int texStateID = CTexture::GetTexState(pTexState);

  const float fSkyBoxSize = SKY_BOX_SIZE;

	if (rd->m_RP.m_nBatchFilter & FB_Z)
	{
		CTexture::s_ptexBlack->Apply(0, texStateID);
		{ // top
			SVF_P3F_C4B_T2F data[] = 
			{
				{Vec3(+fSkyBoxSize, -fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{Vec3(-fSkyBoxSize, -fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{Vec3(+fSkyBoxSize, +fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{Vec3(-fSkyBoxSize, +fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(0, 0)}
			};
			CVertexBuffer vertexBuffer(data,eVF_P3F_C4B_T2F);
			rd->DrawPrimitivesInternal(&vertexBuffer,4, eptTriangleStrip);
		}
		{ // nesw
			SVF_P3F_C4B_T2F data[] = 
			{ 
				{ Vec3(-fSkyBoxSize, -fSkyBoxSize, +fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{ Vec3(-fSkyBoxSize, -fSkyBoxSize, -fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{ Vec3(+fSkyBoxSize, -fSkyBoxSize, +fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{ Vec3(+fSkyBoxSize, -fSkyBoxSize, -fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{ Vec3(+fSkyBoxSize, +fSkyBoxSize, +fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{ Vec3(+fSkyBoxSize, +fSkyBoxSize, -fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{ Vec3(-fSkyBoxSize, +fSkyBoxSize, +fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{ Vec3(-fSkyBoxSize, +fSkyBoxSize, -fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{ Vec3(-fSkyBoxSize, -fSkyBoxSize, +fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{ Vec3(-fSkyBoxSize, -fSkyBoxSize, -fSkyBoxSize), {{0}}, Vec2(0, 0)},
			};
			CVertexBuffer vertexBuffer(data,eVF_P3F_C4B_T2F);
			rd->DrawPrimitivesInternal(&vertexBuffer,10, eptTriangleStrip);
		}
		{	// b
			SVF_P3F_C4B_T2F data[] = 
			{
				{Vec3(+fSkyBoxSize, -fSkyBoxSize, -fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{Vec3(-fSkyBoxSize, -fSkyBoxSize, -fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{Vec3(+fSkyBoxSize, +fSkyBoxSize, -fSkyBoxSize), {{0}}, Vec2(0, 0)},
				{Vec3(-fSkyBoxSize, +fSkyBoxSize, -fSkyBoxSize), {{0}}, Vec2(0, 0)}
			};
			CVertexBuffer vertexBuffer(data,eVF_P3F_C4B_T2F);
			rd->DrawPrimitivesInternal(&vertexBuffer,4, eptTriangleStrip);
		}
	}
	else
	{
		{ // top
			SVF_P3F_C4B_T2F data[] = 
			{
				{Vec3(fSkyBoxSize,-fSkyBoxSize, fSkyBoxSize),  {{0}}, Vec2(1, 1.f-1)},
				{Vec3(-fSkyBoxSize,-fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(0, 1.f-1)},
				{Vec3(fSkyBoxSize, fSkyBoxSize, fSkyBoxSize),  {{0}}, Vec2(1, 1.f-0)},
				{Vec3(-fSkyBoxSize, fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(0, 1.f-0)}
			};

			((CTexture*)(pSky->m_SkyBox[2]))->Apply(0, texStateID);
			CVertexBuffer vertexBuffer(data,eVF_P3F_C4B_T2F);
			rd->DrawPrimitivesInternal(&vertexBuffer,4, eptTriangleStrip);
		}

		Vec3 camera = iSystem->GetViewCamera().GetPosition();
		camera.z = max(0.f,camera.z);

		float fWaterCamDiff = max(0.f,camera.z-m_fTerrainWaterLevel);

		float fMaxDist = gEnv->p3DEngine->GetMaxViewDistance()/1024.f;
		float P = (fWaterCamDiff)/128 + max(0.f,(fWaterCamDiff)*0.03f/fMaxDist);

		P *= m_fSkyBoxStretching;

		float D = (fWaterCamDiff)/10.0f*fSkyBoxSize/124.0f - /*P*/0 + 8;

		D = max(0.f,D);

		if(m_fTerrainWaterLevel>camera.z && SRendItem::m_RecurseLevel[rd->m_RP.m_nProcessThreadID]==1)
		{
			P = (fWaterCamDiff);
			D = (fWaterCamDiff);
		}
	
		float fTexOffset;
		fTexOffset = 1.0f / max(pSky->m_SkyBox[1]->GetHeight(), 1);
		{ // s
			SVF_P3F_C4B_T2F data[] = 
			{ 
				{ Vec3(-fSkyBoxSize,-fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(1.0, 1.f-1.0) },
				{ Vec3(fSkyBoxSize,-fSkyBoxSize, fSkyBoxSize),  {{0}}, Vec2(0.0, 1.f-1.0) },
				{ Vec3(-fSkyBoxSize,-fSkyBoxSize,-P),           {{0}}, Vec2(1.0, 1.f-0.5-fTexOffset) },
				{ Vec3(fSkyBoxSize,-fSkyBoxSize,-P),            {{0}}, Vec2(0.0, 1.f-0.5-fTexOffset) },
				{ Vec3(-fSkyBoxSize,-fSkyBoxSize,-D),           {{0}}, Vec2(1.0, 1.f-0.5-fTexOffset) },
				{ Vec3(fSkyBoxSize,-fSkyBoxSize,-D),            {{0}}, Vec2(0.0, 1.f-0.5-fTexOffset) }
			};

			((CTexture*)(pSky->m_SkyBox[1]))->Apply(0, texStateID);
			CVertexBuffer vertexBuffer(data,eVF_P3F_C4B_T2F);
			rd->DrawPrimitivesInternal(&vertexBuffer,6, eptTriangleStrip);
		}
		{ // e
			SVF_P3F_C4B_T2F data[] = 
			{ 
				{ Vec3(-fSkyBoxSize, fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(1.0, 1.f-0.0) },
				{ Vec3(-fSkyBoxSize,-fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(0.0, 1.f-0.0) },
				{ Vec3(-fSkyBoxSize, fSkyBoxSize,-P),           {{0}}, Vec2(1.0, 1.f-0.5f+fTexOffset) },
				{ Vec3(-fSkyBoxSize,-fSkyBoxSize,-P),           {{0}}, Vec2(0.0, 1.f-0.5f+fTexOffset) },
				{ Vec3(-fSkyBoxSize, fSkyBoxSize,-D),           {{0}}, Vec2(1.0, 1.f-0.5f+fTexOffset) },
				{ Vec3(-fSkyBoxSize,-fSkyBoxSize,-D),           {{0}}, Vec2(0.0, 1.f-0.5f+fTexOffset) }
			};

			CVertexBuffer vertexBuffer(data,eVF_P3F_C4B_T2F);
			rd->DrawPrimitivesInternal(&vertexBuffer,6, eptTriangleStrip);
		}

		fTexOffset = 1.0f / max(pSky->m_SkyBox[0]->GetHeight(), 1);
		{ // n
			SVF_P3F_C4B_T2F data[] = 
			{ 
				{ Vec3(fSkyBoxSize, fSkyBoxSize, fSkyBoxSize),  {{0}}, Vec2(1.0, 1.f-1.0) },
				{ Vec3(-fSkyBoxSize, fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(0.0, 1.f-1.0) },
				{ Vec3(fSkyBoxSize, fSkyBoxSize,-P),            {{0}}, Vec2(1.0, 1.f-0.5-fTexOffset) },
				{ Vec3(-fSkyBoxSize, fSkyBoxSize,-P),           {{0}}, Vec2(0.0, 1.f-0.5-fTexOffset) },
				{ Vec3(fSkyBoxSize, fSkyBoxSize,-D),            {{0}}, Vec2(1.0, 1.f-0.5-fTexOffset) },
				{ Vec3(-fSkyBoxSize, fSkyBoxSize,-D),           {{0}}, Vec2(0.0, 1.f-0.5-fTexOffset) }
			};

			((CTexture*)(pSky->m_SkyBox[0]))->Apply(0, texStateID);
			CVertexBuffer vertexBuffer(data,eVF_P3F_C4B_T2F);
			rd->DrawPrimitivesInternal(&vertexBuffer,6, eptTriangleStrip);
		}
		{ // w
			SVF_P3F_C4B_T2F data[] = 
			{ 
				{ Vec3(fSkyBoxSize,-fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(1.0, 1.f-0.0) },
				{ Vec3(fSkyBoxSize, fSkyBoxSize, fSkyBoxSize), {{0}}, Vec2(0.0, 1.f-0.0) },
				{ Vec3(fSkyBoxSize,-fSkyBoxSize,-P),           {{0}}, Vec2(1.0, 1.f-0.5f+fTexOffset) },
				{ Vec3(fSkyBoxSize, fSkyBoxSize,-P),           {{0}}, Vec2(0.0, 1.f-0.5f+fTexOffset) },
				{ Vec3(fSkyBoxSize,-fSkyBoxSize,-D),           {{0}}, Vec2(1.0, 1.f-0.5f+fTexOffset) },
				{ Vec3(fSkyBoxSize, fSkyBoxSize,-D),           {{0}}, Vec2(0.0, 1.f-0.5f+fTexOffset) }
			};
			CVertexBuffer vertexBuffer(data,eVF_P3F_C4B_T2F);
			rd->DrawPrimitivesInternal(&vertexBuffer,6, eptTriangleStrip);
		}
	}

  rd->FX_PopVP();
  rd->FX_ResetPipe(); 

  return true;
}

static void FillSkyTextureData(CTexture* pTexture, const void* pData, const uint32 width, const uint32 height, const uint32 pitch)
{
	assert(pTexture && pTexture->GetWidth() == width && pTexture->GetHeight() == height);
	CDeviceTexture* pDevTex = pTexture->GetDevTexture();
	assert(pDevTex);

//#if defined(DIRECT3D9) && (defined(WIN32) || defined(WIN64)) // temporarily check for NULL on consoles as well (dev texture might not be available due to texture pool overflowing)
	if (!pDevTex)
		return;
//#endif

#if defined(DIRECT3D9) && !defined(XENON)
	STexLock rect;
	if (SUCCEEDED(pDevTex->LockRect(0, rect, LF_DISCARD)))
	{
		for (uint32 h(0); h<height; ++h)
		{
			const void* pSrc = (const void*)((size_t)pData + h * pitch);
			void* pDst = (void*)((size_t)rect.pData + h * rect.Pitch);
			memcpy(pDst, pSrc, sizeof(CryHalf4) * width);
		}
		pDevTex->UnlockRect(0);
	}
#else
#	if defined(DIRECT3D10)
	gcpRendD3D->m_pd3dDeviceContext->UpdateSubresource(pDevTex->Get2DTexture(), 0, 0, pData, sizeof(CryHalf4) * width, sizeof(CryHalf4) * width * height



		);
#	else
	D3DTexture* pD3DTex = pDevTex->Get2DTexture();
	assert(pD3DTex);
	
	DWORD baseAddress = pD3DTex->Format.BaseAddress << GPU_TEXTURE_ADDRESS_SHIFT;
	
	uint32 flags = 0;
	if (!XGIsPackedTexture(pD3DTex))
		flags |= XGTILE_NONPACKED;
	if (XGIsBorderTexture(pD3DTex))
		flags |= XGTILE_BORDER;

	XGTileTextureLevel(width, height, 0, XGGetGpuFormat(D3DFMT_A16B16G16R16F), flags, (void*) baseAddress, 0, pData, sizeof(CryHalf4) * width, 0);
	//m_pd3dDevice->InvalidateResourceGpuCache(pD3DTex, 0);
#	endif
#endif
}

bool CREHDRSky::mfDraw( CShader *ef, SShaderPass *sfm )
{
	CD3D9Renderer* rd( gcpRendD3D );

#if !defined(_RELEASE)
	if(ef->m_eShaderType != eST_Sky)
	{
		CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Incorrect shader set for sky");
		return false;
	}
#endif


	if( !rd->m_RP.m_pShaderResources || !rd->m_RP.m_pShaderResources->m_pSky )
		return false;

	SSkyInfo* pSky( rd->m_RP.m_pShaderResources->m_pSky );
	if( !pSky->m_SkyBox[0] )
		return false;

	assert(m_pRenderParams);
	if (!m_pRenderParams)
		return false;

	assert(m_pRenderParams->m_pSkyDomeMesh);
	if (!m_pRenderParams->m_pSkyDomeMesh)
		return false;

	bool isNotZPass = (rd->m_RP.m_nBatchFilter & FB_Z) == 0;
	if (isNotZPass)
	{
		// re-create sky dome textures if necessary
		bool forceTextureUpdate(false);
		if (!CTexture::IsTextureExist(m_pSkyDomeTextureMie) || !CTexture::IsTextureExist(m_pSkyDomeTextureRayleigh))
		{
			GenerateSkyDomeTextures(SSkyLightRenderParams::skyDomeTextureWidth, SSkyLightRenderParams::skyDomeTextureHeight);
			forceTextureUpdate = true;
		}

		// dyn tex data lost due to device reset?
		if (m_frameReset != rd->m_nFrameReset)
		{
			forceTextureUpdate = true;
			m_frameReset = rd->m_nFrameReset;
		}

		// update sky dome texture if new data is available
		if (m_skyDomeTextureLastTimeStamp != m_pRenderParams->m_skyDomeTextureTimeStamp || forceTextureUpdate)
		{
			FillSkyTextureData(m_pSkyDomeTextureMie, m_pRenderParams->m_pSkyDomeTextureDataMie, SSkyLightRenderParams::skyDomeTextureWidth, SSkyLightRenderParams::skyDomeTextureHeight, m_pRenderParams->m_skyDomeTexturePitch);
			FillSkyTextureData(m_pSkyDomeTextureRayleigh, m_pRenderParams->m_pSkyDomeTextureDataRayleigh, SSkyLightRenderParams::skyDomeTextureWidth, SSkyLightRenderParams::skyDomeTextureHeight, m_pRenderParams->m_skyDomeTexturePitch);

			// update time stamp of last update
			m_skyDomeTextureLastTimeStamp = m_pRenderParams->m_skyDomeTextureTimeStamp;
		}
	}

	// render
	uint32 nPasses( 0 );
	ef->FXBegin( &nPasses, 0 );
	if( !nPasses )
		return false;
	ef->FXBeginPass( 0 );

	I3DEngine* p3DEngine( gEnv->p3DEngine );

	rd->FX_PushVP();
	rd->m_NewViewport.fMinZ = 0.99f;
	rd->m_bViewportDirty = true;

	if (isNotZPass)
	{
		// shader constants -- set sky dome texture and texel size
		assert(m_pSkyDomeTextureMie && m_pSkyDomeTextureMie->GetWidth() == SSkyLightRenderParams::skyDomeTextureWidth && m_pSkyDomeTextureMie->GetHeight() == SSkyLightRenderParams::skyDomeTextureHeight);
		assert(m_pSkyDomeTextureRayleigh && m_pSkyDomeTextureRayleigh->GetWidth() == SSkyLightRenderParams::skyDomeTextureWidth && m_pSkyDomeTextureRayleigh->GetHeight() == SSkyLightRenderParams::skyDomeTextureHeight);
		Vec4 skyDomeTexSizeVec( (float) SSkyLightRenderParams::skyDomeTextureWidth, (float) SSkyLightRenderParams::skyDomeTextureHeight, 0.0f, 0.0f );
		static CCryNameR Param1Name("SkyDome_TextureSize");
		ef->FXSetPSFloat(Param1Name, &skyDomeTexSizeVec, 1 );
		Vec4 skyDomeTexelSizeVec( 1.0f / (float) SSkyLightRenderParams::skyDomeTextureWidth, 1.0f / (float) SSkyLightRenderParams::skyDomeTextureHeight, 0.0f, 0.0f );
		static CCryNameR Param2Name("SkyDome_TexelSize");
		ef->FXSetPSFloat(Param2Name, &skyDomeTexelSizeVec, 1 );

		// shader constants -- phase function constants
		static CCryNameR Param3Name("SkyDome_PartialMieInScatteringConst");
		static CCryNameR Param4Name("SkyDome_PartialRayleighInScatteringConst");
		static CCryNameR Param5Name("SkyDome_SunDirection");
		static CCryNameR Param6Name("SkyDome_PhaseFunctionConstants");
		ef->FXSetPSFloat(Param3Name, &m_pRenderParams->m_partialMieInScatteringConst, 1 );
		ef->FXSetPSFloat(Param4Name, &m_pRenderParams->m_partialRayleighInScatteringConst, 1 );
		ef->FXSetPSFloat(Param5Name, &m_pRenderParams->m_sunDirection, 1 );
		ef->FXSetPSFloat(Param6Name, &m_pRenderParams->m_phaseFunctionConsts, 1 );

		// shader constants -- night sky relevant constants
		Vec3 nightSkyHorizonCol;
		p3DEngine->GetGlobalParameter( E3DPARAM_NIGHSKY_HORIZON_COLOR, nightSkyHorizonCol );
		Vec3 nightSkyZenithCol;
		p3DEngine->GetGlobalParameter( E3DPARAM_NIGHSKY_ZENITH_COLOR, nightSkyZenithCol );
		float nightSkyZenithColShift( p3DEngine->GetGlobalParameter( E3DPARAM_NIGHSKY_ZENITH_SHIFT ) );	
		const float minNightSkyZenithGradient( -0.1f );

		static CCryNameR Param7Name("SkyDome_NightSkyColBase");
		static CCryNameR Param8Name("SkyDome_NightSkyColDelta");
		static CCryNameR Param9Name("SkyDome_NightSkyZenithColShift");

		Vec4 nsColBase( nightSkyHorizonCol, 0 );
		ef->FXSetPSFloat(Param7Name, &nsColBase, 1 );
		Vec4 nsColDelta( nightSkyZenithCol - nightSkyHorizonCol, 0 );
		ef->FXSetPSFloat(Param8Name, &nsColDelta, 1 );
		Vec4 nsZenithColShift( 1.0f / ( nightSkyZenithColShift - minNightSkyZenithGradient ),  -minNightSkyZenithGradient / ( nightSkyZenithColShift - minNightSkyZenithGradient ) , 0, 0 );
		ef->FXSetPSFloat(Param9Name, &nsZenithColShift, 1 );

		{
			Vec3 mr;
			p3DEngine->GetGlobalParameter(E3DPARAM_SKY_MOONROTATION, mr);
			float moonLati = -gf_PI + gf_PI * mr.x / 180.0f;
			float moonLong = 0.5f * gf_PI - gf_PI * mr.y / 180.0f;
			{
				float sinLonR = sinf(-0.5f * gf_PI);
				float cosLonR = cosf(-0.5f * gf_PI);
				float sinLatR = sinf(moonLati + 0.5f * gf_PI);
				float cosLatR = cosf(moonLati + 0.5f * gf_PI);
				Vec3 moonTexGenRight(sinLonR * cosLatR, sinLonR * sinLatR, cosLonR);

				Vec4 nsMoonTexGenRight(moonTexGenRight, 0);
				static CCryNameR ParamName("SkyDome_NightMoonTexGenRight");
				ef->FXSetVSFloat(ParamName, &nsMoonTexGenRight, 1);
			}
			{
				float sinLonU = sinf(moonLong + 0.5f * gf_PI);
				float cosLonU = cosf(moonLong + 0.5f * gf_PI);
				float sinLatU = sinf(moonLati);
				float cosLatU = cosf(moonLati);
				Vec3 moonTexGenUp(sinLonU * cosLatU, sinLonU * sinLatU, cosLonU);

				Vec4 nsMoonTexGenUp(moonTexGenUp, 0);
				static CCryNameR ParamName("SkyDome_NightMoonTexGenUp");
				ef->FXSetVSFloat(ParamName, &nsMoonTexGenUp, 1);
			}
		}

		Vec3 nightMoonDirection;
		p3DEngine->GetGlobalParameter( E3DPARAM_NIGHSKY_MOON_DIRECTION, nightMoonDirection );
		float nightMoonSize( 25.0f - 24.0f * clamp_tpl( p3DEngine->GetGlobalParameter( E3DPARAM_NIGHSKY_MOON_SIZE ), 0.0f, 1.0f ) );
		Vec4 nsMoonDirSize( nightMoonDirection, nightMoonSize );
		static CCryNameR Param10Name("SkyDome_NightMoonDirSize");
		ef->FXSetVSFloat(Param10Name, &nsMoonDirSize, 1 );
		ef->FXSetPSFloat(Param10Name, &nsMoonDirSize, 1 );

		Vec3 nightMoonColor;
		p3DEngine->GetGlobalParameter( E3DPARAM_NIGHSKY_MOON_COLOR, nightMoonColor );
		Vec4 nsMoonColor( nightMoonColor, 0 );
		static CCryNameR Param11Name("SkyDome_NightMoonColor");
		ef->FXSetPSFloat(Param11Name, &nsMoonColor, 1 );

		Vec3 nightMoonInnerCoronaColor;
		p3DEngine->GetGlobalParameter( E3DPARAM_NIGHSKY_MOON_INNERCORONA_COLOR, nightMoonInnerCoronaColor );
		float nightMoonInnerCoronaScale( 1.0f + 1000.0f * p3DEngine->GetGlobalParameter( E3DPARAM_NIGHSKY_MOON_INNERCORONA_SCALE ) );	
		Vec4 nsMoonInnerCoronaColorScale( nightMoonInnerCoronaColor, nightMoonInnerCoronaScale );
		static CCryNameR Param12Name("SkyDome_NightMoonInnerCoronaColorScale");
		ef->FXSetPSFloat(Param12Name, &nsMoonInnerCoronaColorScale, 1 );

		Vec3 nightMoonOuterCoronaColor;
		p3DEngine->GetGlobalParameter( E3DPARAM_NIGHSKY_MOON_OUTERCORONA_COLOR, nightMoonOuterCoronaColor );
		float nightMoonOuterCoronaScale( 1.0f + 1000.0f * p3DEngine->GetGlobalParameter( E3DPARAM_NIGHSKY_MOON_OUTERCORONA_SCALE ) );
		Vec4 nsMoonOuterCoronaColorScale( nightMoonOuterCoronaColor, nightMoonOuterCoronaScale );
		static CCryNameR Param13Name("SkyDome_NightMoonOuterCoronaColorScale");
		ef->FXSetPSFloat(Param13Name, &nsMoonOuterCoronaColorScale, 1 );
	}

	HRESULT hr(S_OK);

	// commit all render changes
	rd->FX_Commit();

	// set vertex declaration and streams of sky dome
  CRenderMesh* pSkyDomeMesh((CRenderMesh*)m_pRenderParams->m_pSkyDomeMesh);
	hr = rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F);
  if (!FAILED(hr))
  {
	  // set vertex and index buffer
	  pSkyDomeMesh->CheckUpdate(pSkyDomeMesh->_GetVertexFormat(), 0);
    int vbOffset(0);
    int ibOffset(0);
    D3DVertexBuffer *pVB = rd->m_DevBufMan.GetD3DVB(pSkyDomeMesh->_GetVBStream(VSF_GENERAL).m_nID, &vbOffset);
    D3DIndexBuffer *pIB = rd->m_DevBufMan.GetD3DIB(pSkyDomeMesh->_GetIBStream().m_nID, &ibOffset);
    assert(pVB);
    assert(pIB);
		if(!pVB || !pIB)
			return false;

	  hr =  rd->FX_SetVStream(0, pVB, vbOffset, pSkyDomeMesh->GetStreamStride(VSF_GENERAL));

	  ibOffset /= sizeof(uint16);
	  hr = rd->FX_SetIStream(pIB);

	  // draw sky dome
		rd->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, pSkyDomeMesh->_GetNumVerts(), ibOffset, pSkyDomeMesh->_GetNumInds());
  }

  ef->FXEndPass();
  ef->FXEnd();

  if (m_pStars)
	  m_pStars->Render();

  rd->FX_PopVP();

  gcpRendD3D->FX_ResetPipe(); 

	return true;
}

void CStars::Render()
{
	CD3D9Renderer* rd(gcpRendD3D);
	
	I3DEngine* p3DEngine(gEnv->p3DEngine);
	float starIntensity(p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_STAR_INTENSITY));

	//static int s_r_stars(1);
	//static ICVar* s_pCVar_r_stars(0);
	//if (!s_pCVar_r_stars)
	//	s_pCVar_r_stars = REGISTER_CVAR2("r_stars", &s_r_stars, s_r_stars,VF_NULL,"");

	//if (!s_r_stars)
	//	return;

	if (m_pStarMesh && m_pShader && rd->m_RP.m_nPassGroupID == EFSLIST_GENERAL && (rd->m_RP.m_nBatchFilter & FB_GENERAL) && starIntensity > 1e-3f)
	{
		//////////////////////////////////////////////////////////////////////////
		// set shader

		static CCryNameTSCRC shaderTech("Stars");
		m_pShader->FXSetTechnique(shaderTech);
		uint32 nPasses(0);
		m_pShader->FXBegin(&nPasses, FEF_DONTSETTEXTURES|FEF_DONTSETSTATES);
		if (!nPasses)
			return;
		m_pShader->FXBeginPass(0);
		
		//////////////////////////////////////////////////////////////////////////
		// setup params

		int vpX(0), vpY(0), vpWidth(0), vpHeight(0);
		rd->GetViewport(&vpX, &vpY, &vpWidth, &vpHeight);
		const float size = 5.0f;
		float flickerTime(gEnv->pTimer->GetCurrTime());
		static CCryNameR vspnStarSize("StarSize");
#if defined (DIRECT3D9) || defined(PS3)
		Vec4 paramStarSize(size, 0, 0, flickerTime * 0.5f);
#elif defined (DIRECT3D10)
		Vec4 paramStarSize(size / (float) vpWidth, size / (float) vpHeight, 0, flickerTime * 0.5f);
#endif
		m_pShader->FXSetVSFloat(vspnStarSize, &paramStarSize, 1);

















		static CCryNameR pspnStarIntensity("StarIntensity");
		Vec4 paramStarIntensity(starIntensity, 0, 0, 0);
		m_pShader->FXSetPSFloat(pspnStarIntensity, &paramStarIntensity, 1);

		//////////////////////////////////////////////////////////////////////////
		// commit & draw

    int32 nRenderState = GS_BLSRC_ONE | GS_BLDST_ONE;










    rd->FX_SetState( nRenderState );

		rd->FX_Commit();
		if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3S_C4B_T2S)))
    {
		  int offset(0);
		  //void* pVB(m_pStarVB->GetStream(VSF_GENERAL, &offset));
		  //rd->FX_SetVStream(0, pVB, offset, m_VertexSize[m_pStarVB->m_vertexformat]);
		  CRenderMesh* pStarMesh((CRenderMesh*) m_pStarMesh);
		  pStarMesh->CheckUpdate(pStarMesh->_GetVertexFormat(), 0);
      D3DVertexBuffer *pVB = rd->m_DevBufMan.GetD3DVB(pStarMesh->_GetVBStream(VSF_GENERAL).m_nID, &offset);
		  rd->FX_SetVStream(0, pVB, offset, pStarMesh->GetStreamStride(VSF_GENERAL));
		  rd->FX_SetIStream(0);

  #if defined (DIRECT3D9)
		  rd->m_pd3dDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE); // TODO: encapsulate state in renderer!


	#endif

			rd->FX_DrawPrimitive(eptPointList, 0, m_numStars);

	#if defined (DIRECT3D9)
			rd->m_pd3dDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);


  #endif
    }

		m_pShader->FXEndPass();
		m_pShader->FXEnd();
	}
}

bool CREFogVolume::mfDraw( CShader* ef, SShaderPass* sfm )
{
	CD3D9Renderer* rd( gcpRendD3D );

#if !defined(_RELEASE)
	if (ef->m_eShaderType != eST_PostProcess)
	{
		CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Incorrect shader set for fog volume");
		return false;
	}
#endif

	PROFILE_LABEL_PUSH( "FOG_VOLUME" );

	rd->m_RP.m_PersFlags2 |= RBPF2_MSAA_SAMPLEFREQ_PASS;
	rd->FX_SetMSAAFlagsRT();

	// render
	uint32 nPasses( 0 );
	ef->FXBegin( &nPasses, 0 );
	if( 0 == nPasses)
	{
		assert(0);
		rd->m_RP.m_PersFlags2 &= ~RBPF2_MSAA_SAMPLEFREQ_PASS;
		return( false );
	}
	ef->FXBeginPass( 0 );

	if( false != m_viewerInsideVolume )
	{
		rd->SetCullMode( R_CULL_FRONT );
		int nState = GS_COLMASK_RGB | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;
		nState |= m_nearCutoff ? 0 : GS_NODEPTHTEST;
		rd->FX_SetState( nState );
	}
	else
	{
		rd->SetCullMode( R_CULL_BACK );
		rd->FX_SetState( GS_COLMASK_RGB | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA );
	}	

	// set vs constants
	static CCryNameR invObjSpaceMatrixName("invObjSpaceMatrix");
	ef->FXSetVSFloat( invObjSpaceMatrixName, (const Vec4*) &m_matWSInv.m00, 3 );

	const Vec4 cEyePosVec( m_eyePosInWS, !m_viewerInsideVolume ? 1 : 0);
	static CCryNameR eyePosInWSName("eyePosInWS");
	ef->FXSetVSFloat( eyePosInWSName, &cEyePosVec, 1 );

	const Vec4 cEyePosInOSVec( m_eyePosInOS, 0 );
	static CCryNameR eyePosInOSName("eyePosInOS");
	ef->FXSetVSFloat( eyePosInOSName, &cEyePosInOSVec, 1 );

	const Vec4 cNearCutoffVec( m_nearCutoff, m_nearCutoff, m_nearCutoff, m_nearCutoff );
	static CCryNameR nearCutoffName("nearCutoff");
	ef->FXSetVSFloat( nearCutoffName, &cNearCutoffVec, 1 );

	// set ps constants
	const Vec4 cFogColVec( m_fogColor.r, m_fogColor.g, m_fogColor.b, 0 );
	static CCryNameR fogColorName("fogColor");
	ef->FXSetPSFloat( fogColorName, &cFogColVec, 1 );

	const Vec4 cGlobalDensityVec( m_globalDensity, 1.44269502f * m_globalDensity, 0, 0 );
	static CCryNameR globalDensityName("globalDensity");
	ef->FXSetPSFloat( globalDensityName, &cGlobalDensityVec, 1 );

	const Vec4 cDensityOffsetVec( m_densityOffset, m_densityOffset, m_densityOffset, m_densityOffset );
	static CCryNameR densityOffsetName("densityOffset");
	ef->FXSetPSFloat( densityOffsetName, &cDensityOffsetVec, 1 );

	const Vec4 cHeigthFallOffBasePointVec( m_heightFallOffBasePoint, 0 );
	static CCryNameR heightFallOffBasePointName("heightFallOffBasePoint");
	ef->FXSetPSFloat( heightFallOffBasePointName, &cHeigthFallOffBasePointVec, 1 );

	const Vec4 cHeightFallOffDirScaledVec( m_heightFallOffDirScaled, 0 );
	static CCryNameR heightFallOffDirScaledName("heightFallOffDirScaled");
	ef->FXSetPSFloat( heightFallOffDirScaledName, &cHeightFallOffDirScaledVec, 1 );

	const Vec4 cOutsideSoftEdgesLerpVec( m_softEdgesLerp.x, m_softEdgesLerp.y, 0, 0 );
	static CCryNameR outsideSoftEdgesLerpName("outsideSoftEdgesLerp");
	ef->FXSetPSFloat( outsideSoftEdgesLerpName, &cOutsideSoftEdgesLerpVec, 1 );

	const Vec4 cEyePosInWSVec( m_eyePosInWS, 0 );
	ef->FXSetPSFloat( eyePosInWSName, &cEyePosInWSVec, 1 );

	const Vec4 cEyePosInOSx2Vec( 2.0f * m_eyePosInOS, 0 );
	static CCryNameR eyePosInOSx2Name("eyePosInOSx2");
	ef->FXSetPSFloat( eyePosInOSx2Name, &cEyePosInOSx2Vec, 1 );

	// commit all render changes
	rd->FX_Commit();

	// set vertex declaration and streams of skydome
	if (!FAILED(rd->FX_SetVertexDeclaration( 0, eVF_P3F_C4B_T2F )))
  {
	  // define bounding box geometry
	  const uint32 c_numBBVertices( 8 );	
	  SVF_P3F_C4B_T2F bbVertices[ c_numBBVertices ] =
	  {
		  { Vec3( m_localAABB.min.x, m_localAABB.min.y, m_localAABB.min.z ) }, 
		  { Vec3( m_localAABB.min.x, m_localAABB.max.y, m_localAABB.min.z ) }, 
		  { Vec3( m_localAABB.max.x, m_localAABB.max.y, m_localAABB.min.z ) }, 
		  { Vec3( m_localAABB.max.x, m_localAABB.min.y, m_localAABB.min.z ) }, 
		  { Vec3( m_localAABB.min.x, m_localAABB.min.y, m_localAABB.max.z ) }, 
		  { Vec3( m_localAABB.min.x, m_localAABB.max.y, m_localAABB.max.z ) }, 
		  { Vec3( m_localAABB.max.x, m_localAABB.max.y, m_localAABB.max.z ) }, 
		  { Vec3( m_localAABB.max.x, m_localAABB.min.y, m_localAABB.max.z ) }
	  };

	  const uint32 c_numBBIndices( 36 );
	  static const uint16 bbIndices[ c_numBBIndices ] =
	  {
		  0, 1, 2,   0, 2, 3,
		  7, 6, 5,   7, 5, 4,
		  3, 2, 6,   3, 6, 7,
		  4, 5, 1,   4, 1, 0,
		  1, 5, 6,   1, 6, 2,
		  4, 0, 3,   4, 3, 7
	  };	

	  // copy vertices into dynamic VB
	  uint32 nVBOffs;
	  SVF_P3F_C4B_T2F* pVB( (SVF_P3F_C4B_T2F*)rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].LockVB(c_numBBVertices, nVBOffs));
	  memcpy( pVB, bbVertices, c_numBBVertices * sizeof( SVF_P3F_C4B_T2F ) );
	  rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].UnlockVB();

	  // copy indices into dynamic IB
	  uint32 nIBOffs;
	  uint16* pIB(rd->m_DynIB.LockIB(c_numBBIndices, nIBOffs));
	  memcpy(pIB, bbIndices, c_numBBIndices * sizeof(uint16));
	  rd->m_DynIB.UnlockIB();

	  // set streams
	  HRESULT hr( S_OK );
	  hr = rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].Bind();
		assert(SUCCEEDED(hr));
	  hr = rd->m_DynIB.Bind();
		assert(SUCCEEDED(hr));

	  // draw skydome
		rd->FX_DrawIndexedPrimitive(eptTriangleList, nVBOffs, 0, c_numBBVertices, nIBOffs, c_numBBIndices);
  }

	ef->FXEndPass();
	ef->FXEnd();

	rd->m_RP.m_PersFlags2 &= ~RBPF2_MSAA_SAMPLEFREQ_PASS;

	PROFILE_LABEL_POP( "FOG_VOLUME" );

	return( true );
}


bool CREVolumeObject::mfDraw(CShader* ef, SShaderPass* sfm)
{
	CD3D9Renderer* rd(gcpRendD3D);
	I3DEngine* p3DEngine(gEnv->p3DEngine);

  uint32 nFlagsPS2 = rd->m_RP.m_PersFlags2;
	rd->m_RP.m_PersFlags2 &= ~(RBPF2_COMMIT_PF | RBPF2_COMMIT_CM);

	// render
	uint32 nPasses(0);
	ef->FXBegin(&nPasses, 0);
	if (!nPasses)
		return false;

	ef->FXBeginPass(0);

	if (m_nearPlaneIntersectsVolume)
	{
		rd->SetCullMode(R_CULL_FRONT);
		rd->FX_SetState(GS_COLMASK_RGB | GS_NODEPTHTEST | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);
	}
	else
	{
		rd->SetCullMode(R_CULL_BACK );
		rd->FX_SetState(GS_COLMASK_RGB | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);
	}	

	// set vs constants
	static CCryNameR invObjSpaceMatrixName("invObjSpaceMatrix");
	ef->FXSetVSFloat(invObjSpaceMatrixName, (const Vec4*) &m_matInv.m00, 3);

	const Vec4 cEyePosVec(m_eyePosInWS, 0);
	static CCryNameR eyePosInWSName("eyePosInWS");
	ef->FXSetVSFloat(eyePosInWSName, &cEyePosVec, 1);

	const Vec4 cViewerOutsideVec(!m_viewerInsideVolume ? 1 : 0, m_nearPlaneIntersectsVolume ? 1 : 0, 0, 0);
	static CCryNameR viewerIsOutsideName("viewerIsOutside");
	ef->FXSetVSFloat(viewerIsOutsideName, &cViewerOutsideVec, 1);

	const Vec4 cEyePosInOSVec(m_eyePosInOS, 0);
	static CCryNameR eyePosInOSName("eyePosInOS");
	ef->FXSetVSFloat(eyePosInOSName, &cEyePosInOSVec, 1);

	// set ps constants
	const Vec4 cEyePosInWSVec(m_eyePosInWS, 0);
	ef->FXSetPSFloat(eyePosInWSName, &cEyePosInWSVec, 1);
	
	ColorF specColor(1,1,1,1), diffColor(1,1,1,1);
	SRenderShaderResources* pRes(rd->m_RP.m_pShaderResources);
	if (pRes && pRes->m_Constants[eHWSC_Pixel].size())
	{
		ColorF* pSrc = (ColorF*) &pRes->m_Constants[eHWSC_Pixel][0];
		specColor = pSrc[PS_SPECULAR_COL];
		diffColor = pSrc[PS_DIFFUSE_COL];
	}

	Vec3 cloudShadingMultipliers;
	p3DEngine->GetGlobalParameter(E3DPARAM_CLOUDSHADING_MULTIPLIERS, cloudShadingMultipliers);

	Vec3 brightColor(p3DEngine->GetSunColor() * cloudShadingMultipliers.x);
	brightColor = brightColor.CompMul(Vec3(specColor.r, specColor.g, specColor.b));

	Vec3 darkColor(p3DEngine->GetSkyColor() * cloudShadingMultipliers.y);
	darkColor = darkColor.CompMul(Vec3(diffColor.r, diffColor.g, diffColor.b));

	{
		static CCryNameR darkColorName("darkColor");
		const Vec4 data(darkColor, m_alpha);
		ef->FXSetPSFloat(darkColorName, &data, 1);
	}
	{
		static CCryNameR brightColorName("brightColor");
		const Vec4 data(brightColor, m_alpha);
		ef->FXSetPSFloat(brightColorName, &data, 1);
	}

	const Vec4 cVolumeTraceStartPlane(m_volumeTraceStartPlane.n, m_volumeTraceStartPlane.d);
	static CCryNameR volumeTraceStartPlaneName("volumeTraceStartPlane");
	ef->FXSetPSFloat(volumeTraceStartPlaneName, &cVolumeTraceStartPlane, 1);

	const Vec4 cScaleConsts(m_scale, 0, 0, 0);
	static CCryNameR scaleConstsName("scaleConsts");
	ef->FXSetPSFloat(scaleConstsName, &cScaleConsts, 1);

	// TODO: optimize shader and remove need to pass inv obj space matrix
	ef->FXSetPSFloat(invObjSpaceMatrixName, (const Vec4*) &m_matInv.m00, 3);


	// commit all render changes
	rd->FX_Commit();

	// set vertex declaration and streams
	if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
	{
//		static ICVar* s_pCVar = 0;
//		static int s_test = 0;
//
//		if (!s_pCVar)
//			s_pCVar = gEnv->pConsole->Register("r_volobj_new", &s_test, 0);
//
//		if (!s_test)
//		{
//		// define bounding box geometry
//		const uint32 c_numBBVertices(8);
//		SVF_P3F_C4B_T2F bbVertices[c_numBBVertices] =
//		{
//			{Vec3(m_renderBoundsOS.min.x, m_renderBoundsOS.min.y, m_renderBoundsOS.min.z)}, 
//			{Vec3(m_renderBoundsOS.min.x, m_renderBoundsOS.max.y, m_renderBoundsOS.min.z)}, 
//			{Vec3(m_renderBoundsOS.max.x, m_renderBoundsOS.max.y, m_renderBoundsOS.min.z)}, 
//			{Vec3(m_renderBoundsOS.max.x, m_renderBoundsOS.min.y, m_renderBoundsOS.min.z)}, 
//			{Vec3(m_renderBoundsOS.min.x, m_renderBoundsOS.min.y, m_renderBoundsOS.max.z)}, 
//			{Vec3(m_renderBoundsOS.min.x, m_renderBoundsOS.max.y, m_renderBoundsOS.max.z)}, 
//			{Vec3(m_renderBoundsOS.max.x, m_renderBoundsOS.max.y, m_renderBoundsOS.max.z)}, 
//			{Vec3(m_renderBoundsOS.max.x, m_renderBoundsOS.min.y, m_renderBoundsOS.max.z)}
//		};
//
//		const uint32 c_numBBIndices(36);
//		static const uint16 bbIndices[c_numBBIndices] =
//		{
//			0, 1, 2,   0, 2, 3,
//			7, 6, 5,   7, 5, 4,
//			3, 2, 6,   3, 6, 7,
//			4, 5, 1,   4, 1, 0,
//			1, 5, 6,   1, 6, 2,
//			4, 0, 3,   4, 3, 7
//		};	
//
//		// copy vertices into dynamic VB
//		int nVBOffs;
//		SVF_P3F_C4B_T2F* pVB((SVF_P3F_C4B_T2F*) rd->GetVBPtr(c_numBBVertices, nVBOffs, POOL_P3F_COL4UB_TEX2F));
//		memcpy(pVB, bbVertices, c_numBBVertices * sizeof( SVF_P3F_C4B_T2F));
//		rd->UnlockVB(POOL_P3F_COL4UB_TEX2F);
//
//		// copy indices into dynamic IB
//		int nIBOffs;
//		uint16* pIB(rd->GetIBPtr(c_numBBIndices, nIBOffs));
//		memcpy(pIB, bbIndices, c_numBBIndices * sizeof(uint16));
//		rd->UnlockIB();
//
//		// set streams
//		HRESULT hr(S_OK);
//		hr = rd->FX_SetVStream(0, rd->m_pVB[POOL_P3F_COL4UB_TEX2F], 0, sizeof(SVF_P3F_C4B_T2F));
//		hr = rd->FX_SetIStream(rd->m_pIB);
//
//		// draw
//		rd->FX_DrawIndexedPrimitive(eptTriangleList, nVBOffs, 0, c_numBBVertices, nIBOffs, c_numBBIndices);
//		}
//		else
//		{
		CRenderMesh* pHullMesh = (CRenderMesh*) m_pHullMesh;

		// set vertex and index buffer
		pHullMesh->CheckUpdate(pHullMesh->_GetVertexFormat(), 0);
    int vbOffset(0);
    int ibOffset(0);
    D3DVertexBuffer *pVB = rd->m_DevBufMan.GetD3DVB(pHullMesh->_GetVBStream(VSF_GENERAL).m_nID, &vbOffset);
    D3DIndexBuffer *pIB = rd->m_DevBufMan.GetD3DIB(pHullMesh->_GetIBStream().m_nID, &ibOffset);
    assert(pVB);
    assert(pIB);
    if(!pVB || !pIB)
      return false;

		HRESULT hr(S_OK);
		hr = rd->FX_SetVStream(0, pVB, vbOffset, pHullMesh->GetStreamStride(VSF_GENERAL));

		ibOffset /= sizeof(uint16);
		hr = rd->FX_SetIStream(pIB);

		// draw
		rd->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, pHullMesh->_GetNumVerts(), ibOffset, pHullMesh->_GetNumInds());
//		}
	}

	ef->FXEndPass();
	ef->FXEnd();

	rd->FX_ResetPipe();
  rd->m_RP.m_PersFlags2 = nFlagsPS2;

	return true;
}


#if !defined(EXCLUDE_DOCUMENTATION_PURPOSE)
bool CREPrismObject::mfDraw(CShader* ef, SShaderPass* sfm)
{
	CD3D9Renderer* rd(gcpRendD3D);

	// render
	uint32 nPasses(0);
	ef->FXBegin(&nPasses, 0);
	if (!nPasses)
		return false;

	ef->FXBeginPass(0);

	// commit all render changes
//	rd->FX_Commit();

	static SVF_P3F_C4B_T2F pScreenQuad[] =
	{
	{ Vec3(0, 0, 0), 0, Vec2(0, 0) },   
	{ Vec3(0, 1, 0), 0, Vec2(0, 1) },    
	{ Vec3(1, 0, 0), 0, Vec2(1, 0) },   
	{ Vec3(1, 1, 0), 0, Vec2(1, 1) },   
	};

	pScreenQuad[0].xyz = Vec3(0, 0, 0);
	pScreenQuad[1].xyz = Vec3(0, 1, 0);
	pScreenQuad[2].xyz = Vec3(1, 0, 0);
	pScreenQuad[3].xyz = Vec3(1, 1, 0);

	CVertexBuffer strip(pScreenQuad, eVF_P3F_C4B_T2F);
	gcpRendD3D->DrawPrimitivesInternal(&strip, 4, eptTriangleStrip);

	// count rendered polygons
//	rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_nPolygons[rd->m_RP.m_nPassGroupDIP] += 2;
//	rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_nDIPs[rd->m_RP.m_nPassGroupDIP]++;

	ef->FXEndPass();
	ef->FXEnd();

	return true;
}
#endif // EXCLUDE_DOCUMENTATION_PURPOSE


bool CREWaterVolume::mfDraw( CShader* ef, SShaderPass* sfm )
{
	assert( m_pParams );
	if( !m_pParams )
		return false;

	CD3D9Renderer* rd( gcpRendD3D );

#if !defined(_RELEASE)
	if (ef->m_eShaderType != eST_Water)
	{
		CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Incorrect shader set for water / water fog volume");
		return false;
	}
#endif

	if( !m_drawWaterSurface && m_pParams->m_viewerInsideVolume )
	{
		// set projection matrix for full screen quad
		rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj->Push();
		Matrix44A* m = rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj->GetTop();
		mathMatrixOrthoOffCenterLH(m, -1, 1, -1, 1, -1, 1);
		if (SRendItem::m_RecurseLevel[rd->m_RP.m_nProcessThreadID] <= 1)
		{
			const SRenderTileInfo& rti = rd->GetRenderTileInfo();
			if (rti.nGridSizeX>1.f || rti.nGridSizeY>1.f)
			{ // shift and scale viewport
				m->m00 *= rti.nGridSizeX;
				m->m11 *= rti.nGridSizeY;
				m->m30 = -((rti.nGridSizeX-1.f)-rti.nPosX*2.0f);
				m->m31 =  ((rti.nGridSizeY-1.f)-rti.nPosY*2.0f);
			}
		}

		// set view matrix to identity
		rd->PushMatrix();
		rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matView->LoadIdentity();

		rd->EF_DirtyMatrix();
	}

	// render
	uint32 nPasses( 0 );
	ef->FXBegin( &nPasses, 0 );
	if( 0 == nPasses)
	{
		// reset matrices
		rd->PopMatrix();
		rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj->Pop();
		rd->EF_DirtyMatrix();
		return false;
	}
	ef->FXBeginPass( 0 );

	// set ps constants
	if( !m_drawWaterSurface || m_drawFastPath && !m_pParams->m_viewerInsideVolume )
	{
		if( !m_pOceanParams )
		{
			// fog color & density
			Vec4 fogColorDensity( m_pParams->m_fogColor.CompMul( gEnv->p3DEngine->GetSunColor() ), 1.44269502f * m_pParams->m_fogDensity ); // log2(e) = 1.44269502
      static CCryNameR Param1Name("cFogColorDensity");
			ef->FXSetPSFloat(Param1Name, &fogColorDensity, 1 );
		}
		else
		{
			// fog color & density
			Vec4 fogColorDensity( m_pOceanParams->m_fogColor.CompMul( gEnv->p3DEngine->GetSunColor() ), 1.44269502f * m_pOceanParams->m_fogDensity ); // log2(e) = 1.44269502
      static CCryNameR Param1Name("cFogColorDensity");
			ef->FXSetPSFloat(Param1Name, &fogColorDensity, 1 );

			// fog color shallow & water level
			Vec4 fogColorShallowWaterLevel( m_pOceanParams->m_fogColorShallow.CompMul( gEnv->p3DEngine->GetSunColor() ), -m_pParams->m_fogPlane.d );
      static CCryNameR Param2Name("cFogColorShallowWaterLevel");
			ef->FXSetPSFloat(Param2Name, &fogColorShallowWaterLevel, 1 );

			if( m_pParams->m_viewerInsideVolume )
			{
				// under water in-scattering constant term = exp2( -fogDensity * ( waterLevel - cameraPos.z) )
				float c( expf( -m_pOceanParams->m_fogDensity * ( -m_pParams->m_fogPlane.d - rd->GetCamera().GetPosition().z ) ) );
				Vec4 underWaterInScatterConst( c, 0, 0, 0 );
        static CCryNameR Param3Name("cUnderWaterInScatterConst");
				ef->FXSetPSFloat(Param3Name, &underWaterInScatterConst, 1 );
			}
		}

		Vec4 fogPlane( m_pParams->m_fogPlane.n.x, m_pParams->m_fogPlane.n.y, m_pParams->m_fogPlane.n.z, m_pParams->m_fogPlane.d );
    static CCryNameR Param4Name("cFogPlane");
		ef->FXSetPSFloat(Param4Name, &fogPlane, 1 );

		if( m_pParams->m_viewerInsideVolume )
		{
			Vec4 perpDist( m_pParams->m_fogPlane | rd->GetRCamera().Orig, 0, 0, 0 );
      static CCryNameR Param5Name("cPerpDist");
			ef->FXSetPSFloat(Param5Name, &perpDist, 1 );
		}
	}

	// Disable fog when inside volume or when not using fast path - could assign custom RT flag for this instead
	if( m_drawFastPath && m_pParams->m_viewerInsideVolume || !m_drawFastPath && m_drawWaterSurface )
	{
		// fog color & density
		Vec4 fogColorDensity( 0, 0, 0, 0);
		static CCryNameR Param1Name("cFogColorDensity");
		ef->FXSetPSFloat(Param1Name, &fogColorDensity, 1 );
	}

	// set vs constants
	Vec4 viewerColorToWaterPlane( m_pParams->m_viewerCloseToWaterPlane ? 0.0f : 1.0f, 0.0f, 0.0f, 0.0f );
	static CCryNameR Param6Name("cViewerColorToWaterPlane");
	ef->FXSetVSFloat(Param6Name, &viewerColorToWaterPlane, 1 );

	if( m_drawWaterSurface || !m_pParams->m_viewerInsideVolume )
	{
		if (m_pRenderMesh) {
			rd->FX_Commit();

			// set vertex declaration and streams
			if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
			{
				CRenderMesh* pMesh = (CRenderMesh*) m_pRenderMesh;

				// set vertex and index buffer
				pMesh->CheckUpdate(pMesh->_GetVertexFormat(), 0);
				int vbOffset(0);
				int ibOffset(0);
				D3DVertexBuffer *pVB = rd->m_DevBufMan.GetD3DVB(pMesh->_GetVBStream(VSF_GENERAL).m_nID, &vbOffset);
				D3DIndexBuffer *pIB = rd->m_DevBufMan.GetD3DIB(pMesh->_GetIBStream().m_nID, &ibOffset);
				assert(pVB);
				assert(pIB);
				if(!pVB || !pIB)
					return false;

				HRESULT hr(S_OK);
				hr = rd->FX_SetVStream(0, pVB, vbOffset, pMesh->GetStreamStride(VSF_GENERAL));

				ibOffset /= sizeof(uint16);
				hr = rd->FX_SetIStream(pIB);

				eRenderPrimitiveType eType = eptTriangleList;
#if defined(DIRECT3D10) && !defined(PS3) && !defined(CAFE)
				if (CHWShader_D3D::m_pCurInstHS)
					eType = ept3ControlPointPatchList;
#endif
				// draw
				rd->FX_DrawIndexedPrimitive(eType, 0, 0, pMesh->_GetNumVerts(), ibOffset, pMesh->_GetNumInds());
			}
		}
		else {
			// copy vertices into dynamic VB
			uint32 nVBOffs;
			SVF_P3F_C4B_T2F* pVB((SVF_P3F_C4B_T2F*)rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].LockVB(m_pParams->m_numVertices, nVBOffs));
			if (!pVB)
			{
				// reset matrices
				rd->PopMatrix();
				rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj->Pop();
				rd->EF_DirtyMatrix();
				return false;
			}

			memcpy(pVB, m_pParams->m_pVertices, m_pParams->m_numVertices * sizeof(SVF_P3F_C4B_T2F));
			rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].UnlockVB();

			// copy indices into dynamic IB
			uint32 nIBOffs;
			uint16* pIB(rd->m_DynIB.LockIB(m_pParams->m_numIndices, nIBOffs));
			if(!pIB)
			{
				// reset matrices
				rd->PopMatrix();
				rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj->Pop();
				rd->EF_DirtyMatrix();
				return false;
			}
			memcpy(pIB, m_pParams->m_pIndices, m_pParams->m_numIndices * sizeof(uint16));
			rd->m_DynIB.UnlockIB();


			// set streamsw
			HRESULT hr( S_OK );
			hr = rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].Bind();
			hr = rd->m_DynIB.Bind();

			// set vertex declaration
			if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
			{
				// commit all render changes
				rd->FX_Commit();

				// draw
				eRenderPrimitiveType eType = eptTriangleList;
#if defined(DIRECT3D10) && !defined(PS3) && !defined(CAFE)
				if (CHWShader_D3D::m_pCurInstHS)
					eType = ept3ControlPointPatchList;
#endif

				rd->FX_DrawIndexedPrimitive(eType, nVBOffs, 0, m_pParams->m_numVertices, nIBOffs, m_pParams->m_numIndices);
			}
		}
	}
	else
	{
		// copy vertices into dynamic VB
		uint32 nVBOffs;
		SVF_P3F_T3F* pVB( (SVF_P3F_T3F*)rd->m_DynVB[POOL_P3F_TEX3F].LockVB(4, nVBOffs));
		if (!pVB)
		{
			// reset matrices
			rd->PopMatrix();
			rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj->Pop();
			rd->EF_DirtyMatrix();
			return false;
		}

		// Need to offset half a texel...
		// Since we operate in camera space where the viewport goes from (-1, -1) to (1, 1) the offset is 1/width, 
		// 1/height instead of 0.5/width, 0.5/height. Also, y is still flipped so offsetY needs to be inverted.
		int x(0), y(0), w(0), h(0);
		rd->GetViewport(&x, &y, &w, &h);
		float offsetX(-1.0f / (float)w);
		float offsetY(1.0f / (float)h);

#if defined (DIRECT3D10)
     offsetX = 0.0f;
     offsetY = 0.0f;
#endif

		Vec3 coords[8];
		rd->GetRCamera().CalcVerts( coords );

		pVB[0].p.x = -1 + offsetX;
		pVB[0].p.y = 1 + offsetY;
		pVB[0].p.z = 0.5f;
		pVB[0].st = coords[5] - coords[1];

		pVB[1].p.x = 1 + offsetX;
		pVB[1].p.y = 1 + offsetY;
		pVB[1].p.z = 0.5f;
		pVB[1].st = coords[4] - coords[0];

		pVB[2].p.x = -1 + offsetX;
		pVB[2].p.y = -1 + offsetY;
		pVB[2].p.z = 0.5f;
		pVB[2].st = coords[6] - coords[2];

		pVB[3].p.x = 1 + offsetX;
		pVB[3].p.y = -1 + offsetY;
		pVB[3].p.z = 0.5f;
		pVB[3].st = coords[7] - coords[3];

		rd->m_DynVB[POOL_P3F_TEX3F].UnlockVB();

		// set streams
		HRESULT hr( S_OK );
		hr = rd->m_DynVB[POOL_P3F_TEX3F].Bind();

		// set vertex declaration
		if (!FAILED(rd->FX_SetVertexDeclaration( 0, eVF_P3F_T3F )))
    {
		  // commit all render changes
		  rd->FX_Commit();

		  // draw
			rd->FX_DrawPrimitive(eptTriangleStrip, nVBOffs, 4);
    }

		// reset matrices
		rd->PopMatrix();
		rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_matProj->Pop();
		rd->EF_DirtyMatrix();
	}

	ef->FXEndPass();
	ef->FXEnd();

	return true;
}

void CREWaterOcean::Create( uint32 nVerticesCount, SVF_P3F_C4B_T2F *pVertices, uint32 nIndicesCount, uint16 *pIndices)
{
  if( !nVerticesCount || !pVertices || !nIndicesCount || !pIndices)
    return;

  CD3D9Renderer* rd( gcpRendD3D );
  ReleaseOcean();

  m_nVerticesCount = nVerticesCount;
  m_nIndicesCount = nIndicesCount;
  HRESULT hr( S_OK );
#if defined (DIRECT3D9)

  LPDIRECT3DDEVICE9 dv = gcpRendD3D->GetD3DDevice();

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Create vertex buffer
  //////////////////////////////////////////////////////////////////////////////////////////////////

  {
    SVF_P3F_C4B_T2F *dst;
    D3DVertexBuffer* vbuf;

    uint32 size = nVerticesCount * sizeof(SVF_P3F_C4B_T2F);
    hr = dv->CreateVertexBuffer(size , D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, (D3DVertexBuffer**)&m_pVertices, NULL);     
		if(SUCCEEDED(hr) && m_pVertices)
		{
			vbuf = (D3DVertexBuffer*)m_pVertices; 

			hr = vbuf->Lock(0, 0, (void **) &dst, 0);
			if(SUCCEEDED(hr))
			{
				//cryMemcpy(dst, pVertices, nVerticesCount * sizeof(struct_VERTEX_FORMAT_P3F)); 
				memcpy(dst, pVertices, nVerticesCount * sizeof(SVF_P3F_C4B_T2F)); 
				hr = vbuf->Unlock();
			}
			else
				assert(0);
		}
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Create index buffer
  //////////////////////////////////////////////////////////////////////////////////////////////////


  {
    uint32 size = nIndicesCount * sizeof(uint16);
    int flags = 0;
    uint16 *dst;
    D3DIndexBuffer* ibuf;
    hr = dv->CreateIndexBuffer( size, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, (D3DIndexBuffer**)&m_pIndices, NULL);
		if(SUCCEEDED(hr) && m_pIndices)
		{
			ibuf = (D3DIndexBuffer*)m_pIndices;  

			hr = ibuf->Lock(0, 0, (void **) &dst, 0);    
			if(SUCCEEDED(hr))
			{
				//cryMemcpy(dst, pIndices, size);
				memcpy(dst, pIndices, size);
				hr = ibuf->Unlock();
			}
			else
				assert(0);
		}
  }

#elif defined (DIRECT3D10)
  
  D3DDevice *dv = gcpRendD3D->GetD3DDevice();
  HRESULT h;

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Create vertex buffer
  //////////////////////////////////////////////////////////////////////////////////////////////////
  {
    D3DVertexBuffer *pVertexBuffer = 0;
    D3D11_BUFFER_DESC BufDesc;
    SVF_P3F_C4B_T2F *dst = 0;

    uint32 size = nVerticesCount * sizeof(SVF_P3F_C4B_T2F);
    BufDesc.ByteWidth = size;
    BufDesc.Usage = D3D11_USAGE_DEFAULT;
    BufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    BufDesc.CPUAccessFlags = 0;
    BufDesc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA pInitData;
    pInitData.pSysMem = pVertices;
    pInitData.SysMemPitch = 0;
    pInitData.SysMemSlicePitch = 0;

    h = dv->CreateBuffer(&BufDesc, &pInitData, &pVertexBuffer);
/*    if (SUCCEEDED(h))
    {
      byte *pData = (byte*) 0x12345678;
      h = pVertexBuffer->Map(D3D11_MAP_WRITE_DISCARD, 0, (void **)&dst);
      cryMemcpy(dst, pVertices, size);
      pVertexBuffer->Unmap();
    }*/

    m_pVertices = pVertexBuffer;
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Create index buffer
  //////////////////////////////////////////////////////////////////////////////////////////////////
  {
    D3DIndexBuffer *pIndexBuffer = 0;
    uint32 size = nIndicesCount * sizeof(uint16);

    D3D11_BUFFER_DESC BufDesc;
    BufDesc.ByteWidth = size;
    BufDesc.Usage = D3D11_USAGE_DEFAULT;
    BufDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    BufDesc.CPUAccessFlags = 0;
    BufDesc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA pInitData;
    pInitData.pSysMem = pIndices;
    pInitData.SysMemPitch = 0;
    pInitData.SysMemSlicePitch = 0;

    h = dv->CreateBuffer(&BufDesc, &pInitData, &pIndexBuffer);
/*    if (SUCCEEDED(h))
    {
      h = pIndexBuffer->Map(D3D11_MAP_WRITE_DISCARD, 0, (void **)&dst);
      memcpy(dst, pIndices, size);
      pIndexBuffer->Unmap();
    }
*/
    m_pIndices = pIndexBuffer;
  }
#endif
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CREWaterOcean::FrameUpdate()
{
  // Update Water simulator
  //  UpdateFFT();

  static bool bInitialize = true;
  static Vec4 pParams0(0, 0, 0, 0), pParams1(0, 0, 0, 0);

  Vec4 pCurrParams0, pCurrParams1;
  gEnv->p3DEngine->GetOceanAnimationParams(pCurrParams0, pCurrParams1);

  // why no comparison operator on Vec4 ??
  if( bInitialize || pCurrParams0.x != pParams0.x || pCurrParams0.y != pParams0.y ||
    pCurrParams0.z != pParams0.z || pCurrParams0.w != pParams0.w || pCurrParams1.x != pParams1.x || 
    pCurrParams1.y != pParams1.y || pCurrParams1.z != pParams1.z || pCurrParams1.w != pParams1.w )
  {
    pParams0 = pCurrParams0;
    pParams1 = pCurrParams1;
		WaterSimMgr()->Create( 1.0, pParams0.x, pParams0.z, 1.0f, 1.0f);
    bInitialize = false;
  }

  const int nGridSize = 64;

  // Update Vertex Texture
  if ( !CTexture::IsTextureExist(CTexture::s_ptexWaterOcean))
  {
    CTexture::s_ptexWaterOcean->Create2DTexture(nGridSize, nGridSize, 1, 
      FT_DONT_RELEASE | FT_NOMIPS |  FT_USAGE_DYNAMIC, 
      0, eTF_A32B32G32R32F, eTF_A32B32G32R32F);
    CTexture::s_ptexWaterOcean->Fill(ColorF(0, 0, 0, 0));
//		CTexture::s_ptexWaterOcean->SetVertexTexture(true);
  }

   CTexture *pTexture = CTexture::s_ptexWaterOcean;

  // Copy data..
  if (CTexture::IsTextureExist(pTexture))
  {
		const float fUpdateTime = 0.125f*gEnv->pTimer->GetCurrTime();// / clamp_tpl<float>(pParams1.x, 0.55f, 1.0f);
		int nFrameID = gRenDev->GetFrameID();
		void *pRawPtr = NULL;



		WaterSimMgr()->Update(nFrameID, fUpdateTime, false, pRawPtr);
		
		
#if !defined(PS3) // if not running PS3, we need to update the texture in the calling thread context
    Vec4 *pDispGrid = WaterSimMgr()->GetDisplaceGrid();
    if (pDispGrid == NULL) 
      return; 

    uint32 pitch = 4 * sizeof( f32 )*nGridSize; 
    uint32 width = nGridSize; 
    uint32 height = nGridSize;

    STALL_PROFILER("update subresource")
    CDeviceTexture* pDevTex = pTexture->GetDevTexture();
    if (pDevTex == NULL)
      return;
    STexLock rect;












    if (SUCCEEDED(pDevTex->LockRect(0, rect, LF_DISCARD))) 
    {
      cryMemcpy(rect.pData, pDispGrid, 4 * width * height* sizeof(f32) );
      pDevTex->UnlockRect(0);
    }

#endif
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void CREWaterOcean::ReleaseOcean()
{
#if defined (DIRECT3D9)

  IDirect3DVertexBuffer9 *pVertices = (IDirect3DVertexBuffer9*)m_pVertices; 
  IDirect3DIndexBuffer9 *pIndices = (IDirect3DIndexBuffer9*)m_pIndices; 

#elif defined (DIRECT3D10)

  ID3D11Buffer *pVertices = (ID3D11Buffer*)m_pVertices; 
  ID3D11Buffer *pIndices = (ID3D11Buffer*)m_pIndices; 

#endif

  SAFE_RELEASE( pVertices );
  SAFE_RELEASE( pIndices );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

bool CREWaterOcean::mfDraw(  CShader* ef, SShaderPass* sfm  )
{
  if( !m_nVerticesCount || !m_nIndicesCount || !m_pVertices || !m_pIndices)
    return false;

  CD3D9Renderer* rd( gcpRendD3D );

  FrameUpdate();

  int32 nGpuID = 0;// gRenDev->RT_GetCurrGpuID();
  if( CTexture::s_ptexWaterOcean )
  {
#if defined (DIRECT3D10)
    CTexture::s_ptexWaterOcean->SetFilterMode( FILTER_LINEAR );
#else
    CTexture::s_ptexWaterOcean->SetFilterMode( FILTER_POINT );
#endif
    CTexture::s_ptexWaterOcean->SetClampingMode(0, 0, 1);
    CTexture::s_ptexWaterOcean->UpdateTexStates();
  }
	
	if (CTexture::s_ptexWaterRipplesDDN)
	{
		CTexture::s_ptexWaterRipplesDDN->SetVertexTexture(true);
	#if defined (DIRECT3D10)
		CTexture::s_ptexWaterRipplesDDN->SetFilterMode( FILTER_LINEAR );
	#else
		CTexture::s_ptexWaterRipplesDDN->SetFilterMode( FILTER_POINT );
	#endif
		CTexture::s_ptexWaterRipplesDDN->SetClampingMode(0, 0, 1);
		CTexture::s_ptexWaterRipplesDDN->UpdateTexStates();
	}

  //////////////////////////////////////////////////////////////////////////////////////////////////
  //////////////////////////////////////////////////////////////////////////////////////////////////

  uint64 nFlagsShaderRTprev = rd->m_RP.m_FlagsShader_RT;
  rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE4];
	
	// if screen space tessellation
	//rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE3];

  uint32 nFlagsPF2prev = rd->m_RP.m_PersFlags2;
  rd->m_RP.m_PersFlags2 &= ~(RBPF2_COMMIT_PF|RBPF2_COMMIT_CM); 
  
  // render
  uint32 nPasses( 0 );


  // set streams
  HRESULT hr( S_OK );

  STexStageInfo pPrevTexState0 = CTexture::s_TexStages[0];
  STexStageInfo pPrevTexState1 = CTexture::s_TexStages[1];

#if defined (DIRECT3D10)
	STexState pState(FILTER_BILINEAR, false);
#else
	STexState pState(FILTER_POINT, false);
#endif
	const int texStateID(CTexture::GetTexState(pState));


	N3DEngineCommon::SOceanInfo &OceanInfo= gRenDev->m_p3DEngineCommon.m_OceanInfo;
	Vec4 &pParams = OceanInfo.m_vMeshParams;

	uint32 nPrevStateOr = rd->m_RP.m_StateOr;
	uint32 nPrevStateAnd = rd->m_RP.m_StateAnd;

	ef->FXSetTechnique("Water");
	ef->FXBegin( &nPasses, 0 );  

	if( 0 == nPasses)
		return false;

	if( gRenDev->GetRCamera().Orig.z > OceanInfo.m_fWaterLevel ) 
	{
		rd->m_RP.m_StateAnd |= GS_DEPTHFUNC_MASK;		
		rd->m_RP.m_StateOr |= GS_DEPTHWRITE | GS_DEPTHFUNC_LEQUAL;
	}

	ef->FXBeginPass(0);

	if( CTexture::s_ptexWaterOcean )
	{
		CTexture::s_ptexWaterOcean->SetVertexTexture(true);
		CTexture::s_ptexWaterOcean->Apply(0, texStateID);
		CTexture::s_ptexWaterOcean->SetVertexTexture(false);
	}

	if( CTexture::s_ptexWaterRipplesDDN )
	{
		CTexture::s_ptexWaterRipplesDDN->SetVertexTexture(true);
		CTexture::s_ptexWaterRipplesDDN->Apply(1, texStateID);
		CTexture::s_ptexWaterRipplesDDN->SetVertexTexture(false);
	}

	hr= rd->FX_SetVertexDeclaration( 0, eVF_P3F_C4B_T2F );
	if (!FAILED(hr))
	{
		// commit all render changes
		rd->FX_Commit();

		hr = rd->FX_SetVStream(0, m_pVertices, 0, sizeof(SVF_P3F_C4B_T2F));
		hr= rd->FX_SetIStream(m_pIndices);

		eRenderPrimitiveType eType = CRenderer::CV_r_WaterTessellationHW? eptTriangleList:eptTriangleStrip;
#ifdef TESSELLATION_RENDERER
		if (CHWShader_D3D::m_pCurInstHS)
			eType = ept3ControlPointPatchList;
#endif
		rd->FX_DrawIndexedPrimitive(eType, 0, 0, m_nVerticesCount, 0, m_nIndicesCount);  
	}

	ef->FXEndPass();
	ef->FXEnd();

	rd->m_RP.m_StateOr = nPrevStateOr;
	rd->m_RP.m_StateAnd = nPrevStateAnd;

  CTexture::s_TexStages[0] = pPrevTexState0;
  CTexture::s_TexStages[1] = pPrevTexState1;

  gcpRendD3D->FX_ResetPipe(); 

  rd->m_RP.m_FlagsShader_RT = nFlagsShaderRTprev;
  rd->m_RP.m_PersFlags2 = nFlagsPF2prev;

  return true;
}

//=========================================================================================

CREOcclusionQuery::~CREOcclusionQuery()
{
  mfReset();
}

void CREOcclusionQuery::mfReset()
{


#if defined (DIRECT3D9)
  LPDIRECT3DQUERY9  pVizQuery = (LPDIRECT3DQUERY9)m_nOcclusionID;
  SAFE_RELEASE(pVizQuery)
#elif defined (DIRECT3D10)
  ID3D11Query  *pVizQuery = (ID3D11Query*)m_nOcclusionID;
  SAFE_RELEASE(pVizQuery)
#endif
  
  m_nOcclusionID = 0;
  m_nDrawFrame = 0;
  m_nCheckFrame = 0;
  m_nVisSamples = 0;
	m_bSucceeded = false;
}

uint32 CREOcclusionQuery::m_nQueriesPerFrameCounter = 0;
uint32 CREOcclusionQuery::m_nReadResultNowCounter = 0;
uint32 CREOcclusionQuery::m_nReadResultTryCounter = 0;

bool CREOcclusionQuery::mfDraw(CShader *ef, SShaderPass *sfm)
{ 
	PROFILE_FRAME(CREOcclusionQuery::mfDraw);
 
  CD3D9Renderer *r = gcpRendD3D;

	gRenDev->m_cEF.mfRefreshSystemShader("OcclusionTest", CShaderMan::m_ShaderOcclTest);

  CShader *pSh = CShaderMan::m_ShaderOcclTest;
  if( !pSh || pSh->m_HWTechniques.empty())
    return false;

  if (!(r->m_Features & RFT_OCCLUSIONTEST))
  { // If not supported
    m_nVisSamples = r->GetWidth()*r->GetHeight();
    return true;
  }

  int w =  r->GetWidth();
  int h =  r->GetHeight();

  if (!m_nOcclusionID)
  {
    HRESULT hr;


#if defined (DIRECT3D9)
    // Create visibility query
    LPDIRECT3DQUERY9  pVizQuery = NULL;
    
    hr = r->m_pd3dDevice->CreateQuery (D3DQUERYTYPE_OCCLUSION, &pVizQuery);
    if (pVizQuery)
      m_nOcclusionID = (UINT_PTR)pVizQuery;
#elif defined (DIRECT3D10)

    ID3D11Query  *pVizQuery = NULL;
    D3D11_QUERY_DESC qdesc;
    qdesc.MiscFlags = 0; //D3D11_QUERY_MISC_PREDICATEHINT;
    qdesc.Query = D3D11_QUERY_OCCLUSION;
    hr = r->m_pd3dDevice->CreateQuery( &qdesc, &pVizQuery );
    if (pVizQuery)
      m_nOcclusionID = (UINT_PTR)pVizQuery;
#endif
  }

	int nFrame = r->GetFrameID();

  if (!m_nDrawFrame) // only allow queries update, if finished already with previous query
  { // draw test box
    if (m_nOcclusionID)
    {


#if defined (DIRECT3D9)
      D3DQuery*  pVizQuery = (D3DQuery*)m_nOcclusionID;
      pVizQuery->Issue (D3DISSUE_BEGIN);
#elif defined (DIRECT3D10)
			D3DQuery*  pVizQuery = (D3DQuery*)m_nOcclusionID;
			r->m_pd3dDeviceContext->Begin(pVizQuery);
#endif

      /////////////////////////////////////////////////////////////////////////////////////
      /////////////////////////////////////////////////////////////////////////////////////

      uint32 nVertOffs, nIndOffs;

			const t_arrDeferredMeshIndBuff& arrDeferredInds = r->GetDefferedUnitBoxIndexBuffer();
			const t_arrDeferredMeshVertBuff& arrDeferredVerts = r->GetDefferedUnitBoxVertexBuffer();
      
      //allocate vertices
      SVF_P3F_C4B_T2F *pVerts((SVF_P3F_C4B_T2F *)r->m_DynVB[POOL_P3F_COL4UB_TEX2F].LockVB(arrDeferredVerts.size(), nVertOffs));
      memcpy(pVerts, &arrDeferredVerts[0], arrDeferredVerts.size()*sizeof(SVF_P3F_C4B_T2F));
      r->m_DynVB[POOL_P3F_COL4UB_TEX2F].UnlockVB(); 

      //allocate indices
      uint16 *pInds = r->m_DynIB.LockIB(arrDeferredInds.size(), nIndOffs);
      memcpy(pInds, &arrDeferredInds[0], sizeof(uint16)*arrDeferredInds.size());
      r->m_DynIB.UnlockIB();

      r->m_DynVB[POOL_P3F_COL4UB_TEX2F].Bind();
      r->m_DynIB.Bind();

      /////////////////////////////////////////////////////////////////////////////////////
      /////////////////////////////////////////////////////////////////////////////////////

      r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_matView->Push();
      Matrix34 mat;
      mat.SetIdentity();
      mat.SetScale(m_vBoxMax-m_vBoxMin,m_vBoxMin);

			const Matrix44 cTransPosed = GetTransposed44(Matrix44(mat));
      r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_matView->MultMatrixLocal(&cTransPosed);
      r->EF_DirtyMatrix();

      uint32 nPasses;
      pSh->FXSetTechnique("General");
      pSh->FXBegin(&nPasses, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
      pSh->FXBeginPass(0);





      int nPersFlagsSave = r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags;
      int nObjFlagsSave = r->m_RP.m_ObjFlags;
      CRenderObject *pCurObjectSave = r->m_RP.m_pCurObject;
      CShader *pShaderSave = r->m_RP.m_pShader;
      SShaderTechnique *pCurTechniqueSave = r->m_RP.m_pCurTechnique;

      if (r->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F) == S_OK)
      {
        r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags &= ~RBPF_FP_DIRTY | RBPF_FP_MATRIXDIRTY;
        r->m_RP.m_ObjFlags &= ~FOB_TRANS_MASK;
        r->m_RP.m_pCurObject = r->m_RP.m_TempObjects[0][0];
        r->m_RP.m_pShader = pSh;
        r->m_RP.m_pCurTechnique = pSh->m_HWTechniques[0];
        r->FX_SetState(GS_COLMASK_NONE|GS_DEPTHFUNC_LEQUAL); 
        r->SetCullMode(R_CULL_NONE);

        r->FX_Commit();

			  r->FX_DrawIndexedPrimitive(eptTriangleList, nVertOffs, 0, arrDeferredVerts.size(), nIndOffs, arrDeferredInds.size());
      }

      pSh->FXEndPass();
      pSh->FXEnd();

      r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_matView->Pop();
      r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags = nPersFlagsSave;
      r->m_RP.m_ObjFlags = nObjFlagsSave;
      r->m_RP.m_pCurObject = pCurObjectSave;
			r->m_RP.m_pShader = pShaderSave;
      r->m_RP.m_pCurTechnique = pCurTechniqueSave;


#if defined (DIRECT3D9)
      pVizQuery->Issue (D3DISSUE_END);
#elif defined (DIRECT3D10)
			r->m_pd3dDeviceContext->End(pVizQuery);
#endif

			CREOcclusionQuery::m_nQueriesPerFrameCounter++;
			m_nDrawFrame = 1;
    }

		m_bSucceeded = false;
   // m_nDrawFrame = nFrame;
  }

  return true;
}

bool CREOcclusionQuery::mfReadResult_Now()
{
	int nFrame = gcpRendD3D->GetFrameID();




#if defined (DIRECT3D9)
	LPDIRECT3DQUERY9  pVizQuery = (LPDIRECT3DQUERY9)m_nOcclusionID;
	if (pVizQuery)
	{
		HRESULT hRes = S_FALSE;
		while(hRes==S_FALSE)
			hRes = pVizQuery->GetData((void *) &m_nVisSamples, sizeof(DWORD), D3DGETDATA_FLUSH);

		if(hRes == S_OK)
		{
			m_nDrawFrame = 0;
			m_nCheckFrame = nFrame;
		}
	}
#elif defined (DIRECT3D10)
  ID3D11Query  *pVizQuery = (ID3D11Query*)m_nOcclusionID;
  if (pVizQuery)
  {
    HRESULT hRes = S_FALSE;
    while(hRes==S_FALSE)
			hRes = gcpRendD3D->m_pd3dDeviceContext->GetData(pVizQuery, (void *) &m_nVisSamples, sizeof(uint64), 0);

    if(hRes == S_OK)
		{
			m_nDrawFrame = 0;
      m_nCheckFrame = nFrame;
		}

  }
#endif

	m_nReadResultNowCounter ++;

	m_bSucceeded = (m_nCheckFrame == nFrame);
	return m_bSucceeded;
}

bool CREOcclusionQuery::mfReadResult_Try(uint32 nDefaultNumSamples)
{
  return gRenDev->m_pRT->RC_OC_ReadResult_Try(nDefaultNumSamples, this);
}
bool CREOcclusionQuery::RT_ReadResult_Try(uint32 nDefaultNumSamples)
{
	PROFILE_FRAME(CREOcclusionQuery::mfReadResult_Try);

	int nFrame = gcpRendD3D->GetFrameID();










#if defined (DIRECT3D9)
  LPDIRECT3DQUERY9  pVizQuery = (LPDIRECT3DQUERY9)m_nOcclusionID;
  HRESULT hRes = S_OK;
	if (pVizQuery)
	{
		hRes = pVizQuery->GetData((void *) &m_nVisSamples, sizeof(DWORD), 0);

		if (hRes == S_OK)
		{
			m_nDrawFrame = 0;
			m_nCheckFrame = nFrame;
		}
		else
		{
			m_nVisSamples = nDefaultNumSamples;
		}
	}
#elif defined (DIRECT3D10)
  ID3D11Query  *pVizQuery = (ID3D11Query*)m_nOcclusionID;
  if (pVizQuery)
  {
    HRESULT hRes = S_FALSE;
    hRes = gcpRendD3D->m_pd3dDeviceContext->GetData(pVizQuery, (void *) &m_nVisSamples, sizeof(uint64), D3D11_ASYNC_GETDATA_DONOTFLUSH);

    if (hRes == S_OK)
		{
			m_nDrawFrame = 0;
      m_nCheckFrame = nFrame;
		}
  }
#endif

	m_nReadResultTryCounter++;

#ifdef DO_RENDERLOG
  if (!m_nVisSamples)
  {
    if (CRenderer::CV_r_log)
      gRenDev->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], "OcclusionQuery: Water is not visible\n");
  }
  else
  {
    if (CRenderer::CV_r_log)
      gRenDev->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], "OcclusionQuery: Water is visible (%d samples)\n", m_nVisSamples);
  }
#endif

	m_bSucceeded = (m_nCheckFrame == nFrame);
	return m_bSucceeded;
}

bool CREMeshImpl::mfPreDraw(SShaderPass *sl)
{
	FUNCTION_PROFILER_RENDER_FLAT
	assert(m_pRenderMesh);
	if (!m_pRenderMesh)
		return false;
	
	PROFILE_LABEL_SHADER(m_pRenderMesh->GetSourceName() ? m_pRenderMesh->GetSourceName() : "Unknown mesh-resource name");

#if ENABLE_NORMALSTREAM_SUPPORT
  if (CHWShader_D3D::m_pCurInstHS)
  {
    assert(m_pRenderMesh->_HasVBStream(VSF_NORMALS));
  }
#endif

  CRenderMesh *pRM = m_pRenderMesh->_GetVertexContainer();
  assert(pRM->_HasVBStream(VSF_GENERAL) && m_pRenderMesh->_HasIBStream());

  // Should never happen. Video buffer is missing
  if (!pRM->_HasVBStream(VSF_GENERAL) || !m_pRenderMesh->_HasIBStream())
    return false;
  CD3D9Renderer *rd = gcpRendD3D;

#ifdef _DEBUG
  assert(!(pRM->m_IBStream.m_nLockFlags & FSL_WRITE));
  for (int i=0; i<VSF_NUM; i++)
  {
    assert(!(pRM->m_VBStream[i].m_nLockFlags & FSL_WRITE));
    if (!i || (rd->m_RP.m_FlagsStreams_Stream & (1<<i)))
    {
      if (pRM->_IsVBStreamLocked(i))
      {
        assert(0);
      }
    }
  }
#endif

  HRESULT h;
	void* pIB;
	int nOffs;




	{
	  const SMeshDevBuf& MDVBG = pRM->_GetVBStream(VSF_GENERAL);
	  const void *pVB = MDVBG.m_pDevBuf;
	  h = rd->FX_SetVStream(0, pVB, MDVBG.m_nOffset, pRM->GetStreamStride(VSF_GENERAL), rd->m_RP.m_ReqStreamFrequence[0]);

		for (int i=1; i<VSF_NUM; i++)
		{
			if (rd->m_RP.m_FlagsStreams_Stream & (1<<i))
			{
				rd->m_RP.m_PersFlags1 |= RBPF1_USESTREAM<<i;

      	const SMeshDevBuf& MDVBS = pRM->_GetVBStream(i);
      	pVB = MDVBS.m_pDevBuf;
      	h = rd->FX_SetVStream(i, pVB, MDVBS.m_nOffset, pRM->GetStreamStride(i), rd->m_RP.m_ReqStreamFrequence[i]);
			}
			else
			if (rd->m_RP.m_PersFlags1 & (RBPF1_USESTREAM<<i))
			{
				rd->m_RP.m_PersFlags1 &= ~(RBPF1_USESTREAM<<i);
				h = rd->FX_SetVStream(i, NULL, 0, 0, 1);
			}
		}

#ifdef TESSELLATION_RENDERER
    if (CHWShader_D3D::m_pCurInstHS && m_pRenderMesh->m_adjBuffer.m_pSRV)
    {
      // This buffer contains texture coordinates for triangle itself and its neighbors, in total 12 texture coordinates per triangle.
      gcpRendD3D->m_pd3dDeviceContext->DSSetShaderResources(15, 1, &m_pRenderMesh->m_adjBuffer.m_pSRV);
    }
#endif
    {
		  const SMeshDevBuf& MDIB = m_pRenderMesh->_GetIBStream();
  	  assert(MDIB.m_pDevBuf);
		  pIB = MDIB.m_pDevBuf;
  	  nOffs = MDIB.m_nOffset;
    }
	}















	
	assert(pIB);
	h = rd->FX_SetIStream(pIB);
	rd->m_RP.m_IndexOffset = nOffs>>1;


#if defined(CRY_DXPS_RASTERTHREAD)
	if(CD3D9Renderer::UsePS3SoftwareRastizer())
	{
		int32 IdxCount = m_pRenderMesh->_GetNumInds();
		uint16* pIdxBuffer = m_pRenderMesh->LockIB(FSL_READ);
		rd->m_pd3dDevice->SoftRast().IndexBuffer(pIdxBuffer,IdxCount);

		int32 VtxStride = 0;
		void* pVtxBuffer	=	m_pRenderMesh->GetPosPtr(VtxStride, FSL_READ);
		const int	VCount	=	m_pRenderMesh->_GetNumVerts();
		rd->m_pd3dDevice->SoftRast().VertexBuffer(pVtxBuffer,VtxStride,VCount);
	}
#endif

	m_Flags |= FCEF_PRE_DRAW_DONE;

  return true;
}

#if !defined(_RELEASE)
inline bool CREMeshImpl::ValidateDraw(EShaderType shaderType)
{
	bool ret=true;

	if( shaderType != eST_General &&
			shaderType != eST_PostProcess &&
			shaderType != eST_FX &&
			shaderType != eST_Ice &&
			shaderType != eST_Vegetation &&
			shaderType != eST_Terrain &&
			shaderType != eST_Glass &&
			shaderType != eST_Water)
	{
		CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Incorrect shader set for mesh type: %s : %d", m_pRenderMesh->GetSourceName(), shaderType);
		ret = false;
	}

	if(!(m_Flags&FCEF_PRE_DRAW_DONE))
	{
		CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "PreDraw not called for mesh: %s", m_pRenderMesh->GetSourceName());
		ret = false;
	}

	return ret;
}
#endif

bool CREMeshImpl::mfDraw(CShader *ef, SShaderPass *sl)
{
	FUNCTION_PROFILER_RENDER_FLAT
  CD3D9Renderer *r = gcpRendD3D;

#if !defined(_RELEASE)
	if(!ValidateDraw(ef->m_eShaderType))
	{
		return false;
	}
#endif
  
  CRenderMesh *pRM = m_pRenderMesh;
  if (ef->m_HWTechniques.Num())
  {
#if defined(CRY_DXPS_RASTERTHREAD)
		if(CD3D9Renderer::UsePS3SoftwareRastizer() && r->m_RP.m_RendNumGroup<0 && (r->m_RP.m_TI[r->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_SHADOWGEN))
		{
			r->m_pd3dDevice->SoftRast().Draw();
			return true;
		}
#endif
   






		const Matrix34A &mtx = r->m_RP.m_pCurObject->m_II.m_Matrix;
		float flip = (mtx.GetColumn0()^mtx.GetColumn1())*mtx.GetColumn2();
		int cull0	= r->m_RP.m_eCull;
		if (flip<0 && cull0!=eCULL_None)
			r->SetCullMode(cull0==eCULL_Front ? R_CULL_BACK:R_CULL_FRONT);
		else
			flip = 0;

    r->FX_DrawIndexedMesh(r->m_RP.m_RendNumGroup>=0 ? eptHWSkinGroups : pRM->_GetPrimitiveType());    

		if (flip<0)
			r->SetCullMode(cull0);
  }
  
  return true;
}

//===================================================================================

bool CREFlare::mfCheckVis(CRenderObject *obj)
{






  CD3D9Renderer *rd = gcpRendD3D;
  assert(rd->m_pRT->IsRenderThread());
  
  SRenderObjData *pOD = obj->GetObjData(rd->m_RP.m_nProcessThreadID);

  if (!pOD || !pOD->m_pLight)
    return false;

  Vec3 vOrg = obj->GetTranslation();
  bool bVis = false;
  bool bSun = false;

  Vec3 v;  
  v = vOrg - rd->GetRCamera().Orig;  
  if( rd->GetRCamera().ViewDir().Dot(v) < 0.0f)
    return false;

  int32 vp[4];
  rd->GetViewport(&vp[0], &vp[1], &vp[2], &vp[3]);

  Vec3 vx0, vy0;  
  float dist = v.GetLength();

  CREOcclusionQuery *pRE = (CREOcclusionQuery *)pOD->m_pRE;
  if (!pRE || m_nFrameQuery != rd->m_nFrameReset || !pRE->m_nOcclusionID)
  {
    m_nFrameQuery = rd->m_nFrameReset;
    // Create visibility queries
#if defined (DIRECT3D9)
    LPDIRECT3DQUERY9  pVizQuery = NULL;
    HRESULT hr = gcpRendD3D->m_pd3dDevice->CreateQuery (D3DQUERYTYPE_OCCLUSION, &pVizQuery);
#elif defined (DIRECT3D10)
		ID3D11Query* pVizQuery(0);
		D3D11_QUERY_DESC desc;
		desc.Query = D3D11_QUERY_OCCLUSION;
		desc.MiscFlags = 0/*D3D11_QUERY_MISC_PREDICATEHINT*/;
		HRESULT hr(gcpRendD3D->m_pd3dDevice->CreateQuery(&desc, &pVizQuery));
		assert(SUCCEEDED(hr));
#endif
    if (pVizQuery)
    {
      if (!pRE)
        pOD->m_pRE = rd->EF_CreateRE(eDATA_OcclusionQuery);
      pRE = (CREOcclusionQuery *)pOD->m_pRE;
      if (pRE)
      {
        assert(!pRE->m_nOcclusionID);
        pRE->m_nOcclusionID = (UINT_PTR)pVizQuery;
        pRE->m_nVisSamples = 0;
      }
    }
  }
  else if (pRE)
  {
    int nFrame = rd->GetFrameID(); 

    if (pRE->m_nCheckFrame != nFrame)
    {
      if(pRE->m_nCheckFrame)
      {
        pRE->m_nVisSamples=0;
#if defined (DIRECT3D9)
        LPDIRECT3DQUERY9 pVizQuery = (LPDIRECT3DQUERY9)pRE->m_nOcclusionID;
#elif defined (DIRECT3D10)
				ID3D11Query* pVizQuery = (ID3D11Query*)pRE->m_nOcclusionID;
#endif
				// Block until we have a query result
        if (pVizQuery)
        {
          float fTime = iTimer->GetAsyncCurTime();
          bool bInfinite = false;

#if defined (DIRECT3D9)
					while (pVizQuery->GetData(&pRE->m_nVisSamples, sizeof(int32), D3DGETDATA_FLUSH) == S_FALSE)
					{
#elif defined (DIRECT3D10)
					uint64 numVisSamples(0);
					while (gcpRendD3D->m_pd3dDeviceContext->GetData(pVizQuery, (void *)&numVisSamples, sizeof(uint64), 0) == S_FALSE)
					{
						pRE->m_nVisSamples = (int32) numVisSamples;
#endif
            float fDif = iTimer->GetAsyncCurTime() - fTime;
            if (fDif > 0.5f)
            {
              // 5 seconds in the loop
              bInfinite = true;
              break;
            }
          }
#if defined (DIRECT3D10)
          // make sure to update..
          pRE->m_nVisSamples = (int32) numVisSamples;
#endif

          rd->m_RP.m_PS[rd->m_RP.m_nProcessThreadID].m_fOcclusionTime += iTimer->GetAsyncCurTime()-fTime;
          if (bInfinite)
            iLog->Log("Error: Seems like infinite loop in flare occlusion query");
        }
      }
      pRE->m_nCheckFrame = nFrame;
    }
  }

	if (pRE)
	{
		float fMinWidth = 8.0f / (float)rd->GetWidth();
		float fMinHeight = 8.0f / (float)rd->GetHeight();     

		// Clamp minimum size for occlusion query else we'll get accuracy issues like flickering
		vx0 = rd->GetRCamera().X*(dist*0.01f);
		vy0 = rd->GetRCamera().Y*(dist*0.01f);

		CTexture::s_ptexWhite->Apply(0);

		UCol color;
		color.dcolor = ~0;
		uint32 nOffs;
		SVF_P3F_C4B_T2F *vQuad = (SVF_P3F_C4B_T2F *)rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].LockVB(4, nOffs);
		if (!vQuad)
			return true;

		vQuad[0].xyz = vOrg + vx0 + vy0;
		vQuad[0].st = Vec2(0.0f, 0.0f);
		vQuad[0].color = color;

		vQuad[1].xyz = vOrg + vx0 - vy0;
		vQuad[1].st = Vec2(0.0f, 1.0f);
		vQuad[1].color = color;

		vQuad[2].xyz = vOrg - vx0 + vy0; 
		vQuad[2].st = Vec2(1.0f, 0.0f);
		vQuad[2].color = color;

		vQuad[3].xyz = vOrg - vx0 - vy0;
		vQuad[3].st = Vec2(1.0f, 1.0f);
		vQuad[3].color = color;

		rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].UnlockVB();

		// Render the 2 triangles from the data stream
#if defined (DIRECT3D9)  
		LPDIRECT3DQUERY9 pVizQuery = (LPDIRECT3DQUERY9) pRE->m_nOcclusionID;
#elif defined (DIRECT3D10)
		ID3D11Query* pVizQuery = (ID3D11Query*)pRE->m_nOcclusionID;
#endif

		rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].Bind();

		// Andrey said: Set FPMode shouldn't be called here
		// because all shaders have already been setup and
		// changing flags can be dangerous
		uint32 nOldLTFalgs = rd->m_RP.m_FlagsShader_LT;
    rd->FX_SetFPMode();

		if (rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F) != S_OK)
    {
      rd->m_RP.m_FlagsShader_LT = nOldLTFalgs;
      return false;
    }

		rd->FX_SetState(GS_COLMASK_NONE);  
		rd->SetCullMode(R_CULL_NONE);

		CTexture::s_ptexWhite->Apply(0); 

#if defined (DIRECT3D9)  
		HRESULT hr(S_OK);
		hr = pVizQuery->Issue(D3DISSUE_BEGIN);
		assert(SUCCEEDED(hr));
#elif defined (DIRECT3D10)
		rd->m_pd3dDeviceContext->Begin(pVizQuery);
#endif

		rd->FX_DrawPrimitive(eptTriangleStrip, nOffs, 4);

#if defined (DIRECT3D9)  
		hr = pVizQuery->Issue(D3DISSUE_END);
		assert(SUCCEEDED(hr));
#elif defined (DIRECT3D10)
		rd->m_pd3dDeviceContext->End(pVizQuery);
#endif

		Vec3 ProjV[4];
		for (int n=0; n<4; n++)
		{
      Vec3 V = vQuad[n].xyz;
			mathVec3Project(&ProjV[n], &V, vp, &rd->m_ProjMatrix, &rd->m_CameraMatrix, &rd->m_IdentityMatrix);
		}

		float nX = fabsf(ProjV[0].x - ProjV[2].x);
		float nY = fabsf(ProjV[0].y - ProjV[2].y);  
		float area = max(0.15f, nX * nY);          

		float fIntens = (float)pRE->m_nVisSamples/ (area);   

		// Hack: Make sure no flickering occurs due to inaccuracy
		fIntens = clamp_tpl<float>(fIntens*2.0f, 0.0f, 1.0f);  
		if( fIntens < 0.9f) 
			fIntens = 0.0f;

		float fFading = CRenderer::CV_r_coronafade;
		// Accumulate previous frame results and blend in results
		pOD->m_fTempVars[0] = pOD->m_fTempVars[1];
		pOD->m_fTempVars[1] = pOD->m_fTempVars[0] * (1.0f-fFading)  + fIntens * fFading;  

		// restore the LT flags
		rd->m_RP.m_FlagsShader_LT = nOldLTFalgs;
	}

  return true;
}


//static bool useShaft = true;
void CREFlare::InitShaftTex() {
	int w = gcpRendD3D.GetWidth(); 
	int h = gcpRendD3D.GetHeight();
	int flag = FT_NOMIPS | FT_DONT_STREAM;
	SPostEffectsUtils::CreateRenderTarget("$ShaftOccBuffer", CTexture::s_ptexShaftOccBuffer, 
		(int)(w*CTexture::s_fShaftOccBufferRatio), (int)(h*CTexture::s_fShaftOccBufferRatio), false, false, eTF_X8R8G8B8, -1, flag);
	SPostEffectsUtils::CreateRenderTarget("$ShaftBuffer", CTexture::s_ptexShaftBuffer, 
		(int)(w*CTexture::s_fShaftBufferRatio), (int)(h*CTexture::s_fShaftBufferRatio), false, false, eTF_X8R8G8B8, -1, flag);
}
/*
 * params: ef - shader     col - ambient color (alpha as post blending factor)
 */
void CREFlare::mfDrawCorona(CShader *ef, ColorF &col)
{
  CD3D9Renderer *rd = gcpRendD3D;
  CRenderObject *obj = rd->m_RP.m_pCurObject;
  SRenderObjData *pOD = obj->GetObjData(rd->m_RP.m_nProcessThreadID);

  CShader *pShader= ef;
  CDLight *pLight;

  if (!pOD || !(pLight = pOD->m_pLight) || m_Importance > CRenderer::CV_r_coronas )
    return;
    
  // useless check here, as we are using checkVis.
  /*
  v = vOrg - rd->GetRCamera().Orig;  
  if (rd->GetRCamera().ViewDir().Dot(v) < 0.0f)
    return;
  */

	// Compute artist tweakable variables  (scale & intensity)
	//////////////////////////////////////////////////////////////////////////////////////////
	// original size algorithm:
	// (  1 - (viewLen / farplane)   ) ^ Inv(fDistSizeFactor)
	
  float fScaleCorona;// = 0.03f;//m_fScaleCorona;  
  if (pLight->m_fCoronaScale)
   fScaleCorona = pLight->m_fCoronaScale * 0.03f;   // why a magic number "0.03f"?
  else
   return;

	Vec3 lightPos = obj->GetTranslation();
  Vec3 vPrev = lightPos - rd->m_prevCamera.GetPosition();    
  float dist = vPrev.GetLength() / rd->m_prevCamera.GetFarPlane();  //normalized distance  
		
  // Idea: Maybe also adjusting corona size according to it's brightness would look nice  
  // Scale:
  float fDistSizeFactor = m_fDistSizeFactor * pOD->m_pLight->m_fCoronaDistSizeFactor;
	if(fDistSizeFactor <= 0.0f)
		return;
  else if(fDistSizeFactor != 1.0f) 
    fScaleCorona *= cry_powf(1.0f - dist, 1.0f / fDistSizeFactor);
  
  // Decay:
  float fDecay = col[3] * CRenderer::CV_r_coronacolorscale;
  float fDistIntensityFactor = m_fDistIntensityFactor * pOD->m_pLight->m_fCoronaDistIntensityFactor;
	if(fDistIntensityFactor <= 0.0f)
		return;
  else if(fDistIntensityFactor != 1.0f) {
    fDecay *= cry_powf(1.0f - dist, 1.0f / fDistIntensityFactor);
		if( fDecay < 0.001f ) 
			return;
  }
    
	// Get flare color from material and light color
	ColorF pColor = pLight->m_Color;
	SRenderShaderResources* shaderRes = rd->m_RP.m_pShaderResources;
	if ( shaderRes && shaderRes->m_Constants[eHWSC_Pixel].size())
	{    
		ColorF *pSrc = (ColorF *)&shaderRes->m_Constants[eHWSC_Pixel][0];
		pColor *= pSrc[PS_DIFFUSE_COL];
	}
	pColor.a = col.a;
	//////////////////////////////////////////////////////////////////////////////////////////

	
  // Render a normal flare   // TODO: Batch them up. All flares should be rendered by a single DC
  //////////////////////////////////////////////////////////////////////////////////////////
  uint32 nPasses=0;     
	static CCryNameTSCRC techName("Flare");
  pShader->FXSetTechnique(techName);
  pShader->FXBegin(&nPasses, FEF_DONTSETTEXTURES);
  pShader->FXBeginPass(0);

	// Size is texture size x scale (corona scale/base scale(i used 0.2 as reference value))
	float fSize = (fScaleCorona/0.2f)* CRenderer::CV_r_coronasizescale;
  Vec4 artistParams = Vec4( fSize, pLight->m_fCoronaIntensity, fDecay, 0);  // x=scale,   y=intensity,  z=decay,  w=reserved
  static CCryNameR lightMaterialColorName("lightMaterialColor");
	static CCryNameR viewProjMatName("viewProjMat");
	static CCryNameR artistParamName("artistParams");
	pShader->FXSetVSFloat(artistParamName, &artistParams, 1 );
	pShader->FXSetVSFloat(lightMaterialColorName, alias_cast<Vec4*>(&pColor), 1 );
  pShader->FXSetVSFloat(viewProjMatName, alias_cast<Vec4*>(rd->m_CameraProjMatrix.GetData()), 4);
  
  
	// bind base texture:
	static STexState bilinearTS(FILTER_LINEAR,true);
	SEfResTexture *pSpriteTex = rd->m_RP.m_pShaderResources->m_Textures[EFTT_DIFFUSE];
	if( pSpriteTex && pSpriteTex->m_Sampler.m_pTex )
		pSpriteTex->m_Sampler.m_pTex->Apply(0, CTexture::GetTexState(bilinearTS) );

  // TODO: Don't enable Color and TC stream (the problem is, CE3 currently doesn't have a built-in VF def for that):
  //rd->DrawQuad(0.5f, 0.5f, 0, vOrg.x, vOrg.y, vOrg.z);  // This doesn't work
  rd->DrawQuad(lightPos.x, lightPos.y, lightPos.x, lightPos.y, pColor, lightPos.z);
  

  pShader->FXEndPass(); 
  //////////////////////////////////////////////////////////////////////////////////////////
  
  // Render optional shafts
  //////////////////////////////////////////////////////////////////////////////////////////
	// check if option is enabled, including:
	//		global switch, per-entity spec threshhold and material pass count (< 4  ==  not enabled)
	if( CRenderer::CV_r_coronashafts == 0 || 
			pLight->m_nCoronaShaftsMinSpec > rd->EF_GetShaderQuality(eST_FX) || 
			nPasses < 4 ) 
	{
		// shafts not enabled; terminate render path.
		pShader->FXEnd(); 
		return;
	}
	
	// lazy initialization
	if( !CTexture::s_ptexShaftOccBuffer || !CTexture::s_ptexShaftBuffer )
		InitShaftTex();
		
	static CCryNameR frustumName("frustumParams");
	static CCryNameR shaftSizeName("shaftSizeParams");
	static CCryNameR shaftAppearanceName("shaftAppearanceParams");
  
  // Render Occ map
  // params: view space near & far plane, shaftSprite, shaftSizeParams
  rd->FX_PushRenderTarget( 0, CTexture::s_ptexShaftOccBuffer, NULL, true, -1, false );
  ColorF clearClr(0,0,0,1);
  rd->ClearBuffer( FRT_CLEAR_COLOR, &clearClr );  // TODO: enable ghost blending
  pShader->FXBeginPass(1);
		// Camera frustum vars
		const CRenderCamera *cam = &rd->GetRCamera();
		Vec4 frustumVars( cam->Near, cam->Far, 0, 0 );
		Vec4 shaftSizeVars( pLight->m_fShaftSrcSize, pLight->m_fShaftLength,  0, 0 );
		pShader->FXSetVSFloat( artistParamName, &artistParams, 1 );
		pShader->FXSetVSFloat( viewProjMatName, (Vec4*)rd->m_CameraProjMatrix.GetData(), 4);
		pShader->FXSetVSFloat( frustumName, &frustumVars, 1 );
		pShader->FXSetVSFloat( shaftSizeName, &shaftSizeVars, 1 );
		CTexture::s_ptexZTargetScaled->Apply( 0,  CTexture::GetTexState(bilinearTS) );
		SEfResTexture *pShaftTex = rd->m_RP.m_pShaderResources->m_Textures[EFTT_CUSTOM];
		if( pShaftTex && pShaftTex->m_Sampler.m_pTex )   
			pShaftTex->m_Sampler.m_pTex->Apply(1, CTexture::GetTexState(bilinearTS) );
		rd->DrawQuad(lightPos.x, lightPos.y, lightPos.x, lightPos.y, pColor, lightPos.z);
  pShader->FXEndPass();
  rd->FX_PopRenderTarget(0);
  
	// Gen shafts
	// params: shaftSizeParams, shaftAppearanceParams, occBuffer, spriteTex
	rd->FX_PushRenderTarget( 0, CTexture::s_ptexShaftBuffer, NULL, true, -1, false );
	rd->ClearBuffer( FRT_CLEAR_COLOR, &clearClr );
	pShader->FXBeginPass(2);
		Vec4 shaftAppearanceVars( pLight->m_fShaftBrightness, pLight->m_fShaftDecayFactor, pLight->m_fShaftBlendFactor, 0 );
		pShader->FXSetVSFloat(artistParamName, &artistParams, 1 );
		pShader->FXSetVSFloat(viewProjMatName, (Vec4*)rd->m_CameraProjMatrix.GetData(), 4);
		pShader->FXSetVSFloat( shaftSizeName, &shaftSizeVars, 1 );
		pShader->FXSetPSFloat(shaftAppearanceName, &shaftAppearanceVars, 1);
		CTexture::s_ptexShaftOccBuffer->Apply(0,  CTexture::GetTexState(bilinearTS));
		rd->DrawQuad(lightPos.x, lightPos.y, lightPos.x, lightPos.y, pColor, lightPos.z);
	pShader->FXEndPass();
	rd->FX_PopRenderTarget(0);
	
	// Blend
	// params: lightMaterialColor, shaftAppearanceParams, shaftBuffer
	pShader->FXBeginPass(3);
		pShader->FXSetPSFloat(lightMaterialColorName, alias_cast<Vec4*>(&pColor), 1 );
		pShader->FXSetPSFloat(shaftAppearanceName, &shaftAppearanceVars, 1);
		CTexture::s_ptexShaftBuffer->Apply(0,  CTexture::GetTexState(bilinearTS));
		rd->DrawQuad(lightPos.x, lightPos.y, lightPos.x, lightPos.y, pColor, lightPos.z);
	pShader->FXEndPass();
  
  pShader->FXEnd();
}

static float sInterpolate(float& pprev, float& prev, float& next, float& nnext, float ppweight, float pweight, float nweight, float nnweight)
{
  return pprev*ppweight + prev*pweight + next*nweight + nnext*nnweight;
}

static float sSpline(float x)
{
  float fX = fabsf(x);

  if(fX > 2.0f)
    return 0;
  if(fX > 1.0f)
    return (2.0f-fX)*(2.0f-fX)*(2.0f-fX)/6.0f;
  return 2.0f/3.0f-fX*fX+0.5f*fX*fX*fX;
}

bool CREFlare::mfDraw(CShader *ef, SShaderPass *sfm)
{
  CD3D9Renderer *rd = gcpRendD3D;
  assert(rd->m_pRT->IsRenderThread());

  if (!CRenderer::CV_r_coronas)
    return false;

#if defined( PS3 )
	// todo: occlusion queries for flares needs to be implemented
	return false;
#endif

  int nThreadID = rd->m_RP.m_nProcessThreadID;
  rd->m_RP.m_TI[nThreadID].m_matView->LoadMatrix((Matrix44*)rd->m_CameraMatrix.GetData());

  CRenderObject *obj = rd->m_RP.m_pCurObject;
  SRenderObjData *pOD = obj->GetObjData(nThreadID);
    
  if (!mfCheckVis(obj))
    return false;

  // Restore current object
  rd->m_RP.m_pCurObject = obj;    
  
  float fBrightness = pOD->m_fTempVars[1];
  fBrightness = clamp_tpl<float>(fBrightness, 0.0f, 1.0f);    
  if(!fBrightness)
  {
    return false;
  }

  obj->m_II.m_AmbColor.r = obj->m_II.m_AmbColor.g = obj->m_II.m_AmbColor.b = 1;  
  obj->m_II.m_AmbColor.a = fBrightness;

  mfDrawCorona(ef, obj->m_II.m_AmbColor);
  
  // Disabled for now as it is not working - lens-flare
  // mfDrawFlares(ef, obj->m_Color);

  return true;
} 

void CRenderMesh::DrawImmediately()
{
  CD3D9Renderer *rd = gcpRendD3D;

  HRESULT hr = rd->FX_SetVertexDeclaration(0, _GetVertexFormat());

  if (FAILED(hr))
  {
    assert(!"CRenderMesh::DrawImmediately failed");
    return;
  }

  // set vertex and index buffer
  CheckUpdate(_GetVertexFormat(), 0);

  int vbOffset(0);
  int ibOffset(0);
  D3DVertexBuffer *pVB = rd->m_DevBufMan.GetD3DVB(_GetVBStream(VSF_GENERAL).m_nID, &vbOffset);
  D3DIndexBuffer *pIB = rd->m_DevBufMan.GetD3DIB(_GetIBStream().m_nID, &ibOffset);
  assert(pVB);
  assert(pIB);

  if (!pVB || !pIB)
  {
    assert(!"CRenderMesh::DrawImmediately failed");
    return;
}

  hr =  rd->FX_SetVStream(0, pVB, vbOffset, GetStreamStride(VSF_GENERAL));

  ibOffset /= sizeof(uint16);
  hr = rd->FX_SetIStream(pIB);

  // draw indexed mesh
	rd->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, _GetNumVerts(), ibOffset, _GetNumInds());
}

bool CREHDRProcess::mfDraw(CShader *ef, SShaderPass *sfm)
{
  CD3D9Renderer *rd = gcpRendD3D;
  assert(rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_HDR || rd->m_RP.m_CurState & GS_WIREFRAME);
  if (!(rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_HDR))
    return false;

  rd->FX_HDRPostProcessing();
  return true;
}

bool CREBeam::mfDraw(CShader *ef, SShaderPass *sl)
{  
  CD3D9Renderer *rd = gcpRendD3D;

  if (SRendItem::m_RecurseLevel[rd->m_RP.m_nProcessThreadID]!=1)
    return false;

  EShaderQuality nShaderQuality = (EShaderQuality) gcpRendD3D->EF_GetShaderQuality(eST_FX);
  ERenderQuality nRenderQuality = gRenDev->m_RP.m_eQuality;
  bool bLowSpecShafts = (nShaderQuality == eSQ_Low) || (nRenderQuality == eRQ_Low);
	uint32 currCommitFlags = rd->m_RP.m_nCommitFlags;

  bool bUseOptBeams = CRenderer::CV_r_beams == 3 && (CRenderer::CV_r_HDRRendering || CRenderer::CV_r_PostProcess);
  
  CTexture *pShaftsRT = CTexture::s_ptexGlow[0];
  
  // If HDR active, render to floating point buffer instead
  if( CRenderer::CV_r_HDRRendering > 0 )
    pShaftsRT = CTexture::s_ptexHDRTargetScaled[2];
  
  CRenderObject *pObj = rd->m_RP.m_pCurObject;
  SRenderObjData *pOD = pObj->GetObjData(rd->m_RP.m_nProcessThreadID);

  if((!pShaftsRT && bUseOptBeams) || !pObj || !pOD)   
    return 0;
  
  int vX, vY, vWidth, vHeight;
  rd->GetViewport(&vX, &vY, &vWidth, &vHeight);

  CRenderCamera cam;
  SRenderLight *pLight = pOD->m_pLight;
  cam.Perspective(DEG2RAD(pLight->m_fLightFrustumAngle*2.0f), 1, 0.01f, pLight->m_fRadius); 
  Vec3 vForward = pObj->m_II.m_Matrix.GetColumn(0);
  Vec3 vUp = pObj->m_II.m_Matrix.GetColumn(2);
  cam.LookAt(pLight->m_Origin, pLight->m_Origin+vForward, vUp);
  Vec3 vPoints[8];
  cam.CalcVerts(vPoints);
  const CRenderCamera& rcam = rd->GetRCamera();
  int i;
  float fNearDist = FLT_MAX;
  float fFarDist = -FLT_MAX;
  Plane pNear;
  Plane pFar;

  for (i=0; i<8; i++)
  {
	  Plane p = Plane::CreatePlane(rcam.Z, vPoints[i]);
    float fDist = p.DistFromPlane(rcam.Orig);
    if (fNearDist > fDist)
    {
      fNearDist = fDist;
      pNear = p;
    }
    if (fFarDist < fDist)
    {
      fFarDist = fDist;
      pFar = p; 
    }
  }

  if (fFarDist <= 0)  
    return true;

  if( bLowSpecShafts || CRenderer::CV_r_beams == 4)
  {
#ifdef DO_RENDERLOG
    if (rd->m_LogFile)
      rd->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], " +++ Draw low spec beam for light '%s' (%.3f, %.3f, %.3f) +++ \n", pLight->m_sName ? pLight->m_sName : "<Unknown>", pLight->m_Origin[0], pLight->m_Origin[1], pLight->m_Origin[2]);
#endif

		gRenDev->m_cEF.mfRefreshSystemShader("LightFlares", CShaderMan::m_ShaderLightFlares);

    CShader *pShader= CShaderMan::m_ShaderLightFlares;

    rd->FX_ResetPipe();
    STexState pTexState;
    pTexState.SetFilterMode(FILTER_TRILINEAR);        
    pTexState.SetClampMode(1, 1, 1);  

    STexState pTexStateSec;
    pTexStateSec.SetFilterMode(FILTER_POINT);        
    pTexStateSec.SetClampMode(0, 0, 0);  
      
    int vp[4];
    rd->GetViewport(&vp[0], &vp[1], &vp[2], &vp[3]);

    // Get flare color from material and light color
    ColorF pColor = pLight->m_Color;

    if (rd->m_RP.m_pShaderResources && rd->m_RP.m_pShaderResources->m_Constants[eHWSC_Pixel].size())
    {    
      ColorF *pSrc = (ColorF *)&rd->m_RP.m_pShaderResources->m_Constants[eHWSC_Pixel][0];
      pColor *= pSrc[PS_DIFFUSE_COL];
    }

    Matrix44A mProjMatrix = rd->m_ProjMatrix;
    Matrix44A mCameraMatrix = rd->m_CameraMatrix;

    // Get light frustum bounding rectangle
    Vec2 pMin(vWidth, vHeight), pMax(0, 0);
    for( int p = 0; p < 8; ++p )
    {
      Vec3 vProj = Vec3(0,0,0);
      mathVec3Project(&vProj, &vPoints[p], vp, &mProjMatrix, &mCameraMatrix, &rd->m_IdentityMatrix);  	  
      pMin.x = min(pMin.x, vProj.x);
      pMin.y = min(pMin.y, vProj.y);
      pMax.x = max(pMax.x, vProj.x);
      pMax.y = max(pMax.y, vProj.y);
    }

    Vec2 pMed = (pMax + pMin) *0.5f;
    /*
    pMin.x = max(pMin.x, 0.0f);
    pMin.y = max(pMin.y, 0.0f);
    pMax.x = min(pMax.x, (float)vWidth);
    pMax.y = min(pMax.y, (float)vHeight);*/

    // Set orthogonal ViewProj matrix
    rd->Set2DMode(true, rd->GetWidth(), rd->GetHeight());

    // Render light beam flares
    uint32 nPasses=0;     
    static CCryNameTSCRC techName("LowSpecBeams"); 
    pShader->FXSetTechnique(techName);
    pShader->FXBegin(&nPasses, FEF_DONTSETSTATES|FEF_DONTSETTEXTURES);
    pShader->FXBeginPass(0);

    Vec4 pParams= Vec4(pColor.r, pColor.g, pColor.b, pColor.a);            
    static CCryNameR cFlareColorName("cFlareColor");
    
    rd->FX_SetState(GS_DEPTHFUNC_LEQUAL | GS_BLSRC_ONE |GS_BLDST_ONEMINUSSRCCOL);       
    rd->SetCullMode(R_CULL_NONE);   

    // Adjudst radius scale according to volume size on screen
    float fRadScale = (pMed - pMax).GetLength();
    fRadScale = min(fRadScale, (float) vWidth);

    // Adjust amount of planes according to light size
    int nNumPlanes = max( 10, int_round( floorf(pLight->m_fRadius*0.5f) ) );  
    float fPlaneStep = pLight->m_fRadius ;

    float fSizeStep = 1.0f / (float)nNumPlanes;
    for(int p = 0; p < nNumPlanes; ++p)
    {
      Vec3 vOrg= Vec3(0,0,0), v= Vec3(0,0,0);
      float fIncr =  ((float)p)/ (float)nNumPlanes;
      vOrg = pLight->m_Origin  + fPlaneStep *(fIncr*fIncr) * vForward;

      v = vOrg - rd->GetRCamera().Orig;  
      // cull
      if( rd->GetRCamera().ViewDir().Dot(v) < 0.0f)
        continue;

      float fInvRadius = pLight->m_fRadius;
      if (fInvRadius <= 0.0f)
        fInvRadius = 1.0f;

      fInvRadius = 1.0f / fInvRadius;

      // light position
      Vec3 pLightVec = pLight->m_Origin - vOrg;

      // compute attenuation
      pLightVec *= fInvRadius;
      float fAttenuation = clamp_tpl<float>(1.0f - (pLightVec.x * pLightVec.x + pLightVec.y * pLightVec.y + pLightVec.z * pLightVec.z), 0.0f, 1.0f);

      Vec3 vScr = Vec3(0,0,0);
      mathVec3Project(&vScr, &vOrg, vp, &mProjMatrix, &mCameraMatrix, &rd->m_IdentityMatrix);

      // Get normalized distance  
      float fD = v.GetLength();
      float fP = rd->GetRCamera().Far;
      float fDist =   min(100.0f*fD / fP, 1.0f);

      // compute size and attenuation factors
      float fShaftSliceSize = fRadScale* (min(pLight->m_fLightFrustumAngle * 2.0f, 60.0f)/90.0f) * 0.5f;
      float fDistSizeFactor = fShaftSliceSize/fDist; 
      float fNearPlaneSoftIsec = min(fD/2.0f, 1.0f); 
      
      pParams= Vec4(pColor.r, pColor.g, pColor.b, 1.0f)* fSizeStep * fNearPlaneSoftIsec * fAttenuation;
      pParams.w = fAttenuation;

      pShader->FXSetPSFloat(cFlareColorName, &pParams, 1);

      ITexture *pLightTexture = pLight->GetLightTexture();
      if( pLightTexture )
        ((CTexture *)pLightTexture)->Apply(0, CTexture::GetTexState(pTexState));
      else
        CTexture::s_ptexWhite->Apply(0, CTexture::GetTexState(pTexState));

      float fSize= fDistSizeFactor * (fSizeStep * ((float)p + 1.0f));

      //todo: merge geometry
      rd->DrawQuad(vScr.x-fSize, vScr.y-fSize, vScr.x+fSize, vScr.y+fSize, pColor, vScr.z);        
    }

    pShader->FXEndPass(); 
    pShader->FXEnd();

    rd->Set2DMode(false, rd->GetWidth(), rd->GetHeight());

    return true;
  }

  if (gRenDev->m_LogFile)
    gRenDev->Logv(SRendItem::m_RecurseLevel[gRenDev->m_RP.m_nProcessThreadID], " +++ Draw beam for light '%s' (%.3f, %.3f, %.3f) +++ \n", pLight->m_sName ? pLight->m_sName : "<Unknown>", pLight->m_Origin[0], pLight->m_Origin[1], pLight->m_Origin[2]);


  CHWShader_D3D *curVS = (CHWShader_D3D *)sl->m_VShader;
  CHWShader_D3D *curPS = (CHWShader_D3D *)sl->m_PShader;

  if (!curPS || !curVS)
    return false;

  uint32 nCasters = 0;
  ShadowMapFrustum* pFr = NULL;
  SShaderTechnique *pTech = rd->m_RP.m_pCurTechnique;
  uint64 nCurrFlagShader_RT = rd->m_RP.m_FlagsShader_RT;
  

  // We will draw the slices in world space
  // So set identity object
  rd->m_RP.m_pCurObject = rd->m_RP.m_Objects[0];
  rd->m_RP.m_LPasses[0].nLights = 1;
  rd->m_RP.m_LPasses[0].pLights[0] = pOD->m_pLight;
  CHWShader_D3D::mfSetLightParams(0);

  // Setup clip planes
  Plane clipPlanes[6];
  for (i=0; i<6; i++)
  {
    switch (i)
    {
    case 0:
      clipPlanes[i] = Plane::CreatePlane(vPoints[0], vPoints[7], vPoints[3]);
      break;
    case 1:
      clipPlanes[i] = Plane::CreatePlane(vPoints[1], vPoints[4], vPoints[0]);      
      break;
    case 2:
      clipPlanes[i] = Plane::CreatePlane(vPoints[2], vPoints[5], vPoints[1]);
      break;
    case 3:
      clipPlanes[i] = Plane::CreatePlane(vPoints[3], vPoints[6], vPoints[2]);
      break;
    case 4:
      clipPlanes[i] = Plane::CreatePlane(vPoints[0], vPoints[2], vPoints[1]);
      break;
    case 5:
      clipPlanes[i] = Plane::CreatePlane(vPoints[6], vPoints[4], vPoints[5]);
      break;
    }
    if (CRenderer::CV_r_beamssoftclip == 0)
    {
      Plane pTr = TransformPlane2(rd->m_InvCameraProjMatrix, clipPlanes[i]);
#if defined (DIRECT3D9)
      rd->m_pd3dDevice->SetClipPlane(i, &pTr.n[0]);
#elif defined (DIRECT3D10)
      assert(0);
#endif
    }
  }

  if (CRenderer::CV_r_beamssoftclip == 0)
  {
#if defined (DIRECT3D9)
    rd->m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0x3f);
#elif defined (DIRECT3D10)
    assert(0);
#endif
  }

  float fDistNear = pNear.DistFromPlane(rcam.Orig);
  float fDistFar = pFar.DistFromPlane(rcam.Orig);
  float fDist = fDistFar - fDistNear;
  float fDistBetweenSlices = CRenderer::CV_r_beamsdistfactor;
  if (fDistNear > 100.0f) 
    fDistBetweenSlices *= fDistNear * 0.01f;
  if (fDistNear < 0) fDistNear = 0;
  if (fDistFar < 0)  fDistFar = 0;
  int nSlices = (int)(fabsf(fDistFar - fDistNear) / fDistBetweenSlices);
  if (nSlices > CRenderer::CV_r_beamsmaxslices)
    fDistBetweenSlices = fabsf(fDistFar - fDistNear) / (float)CRenderer::CV_r_beamsmaxslices;

  float fStartDist = pNear.d; 
  float fEndDist = pFar.d;
  if (pNear.d > pFar.d)
  {
    Exchange(fStartDist, fEndDist);
  }

  float fCurDist = fStartDist;
  float fIncrDist = fDistBetweenSlices;

  ColorF col;
  col.r = col.g = col.b = fDistBetweenSlices / fDist;    
  col.a = 1.0f;
  if (CRenderer::CV_r_beamshelpers)
    col = Col_White;

  SRenderShaderResources Res;
  SRenderShaderResources *pRes = rd->m_RP.m_pShaderResources;
  Res.m_Constants[eHWSC_Pixel].resize(4);
  Res.m_Constants[eHWSC_Pixel][PS_DIFFUSE_COL][0] = col[0];
  Res.m_Constants[eHWSC_Pixel][PS_DIFFUSE_COL][1] = col[1];
  Res.m_Constants[eHWSC_Pixel][PS_DIFFUSE_COL][2] = col[2];
  Res.m_Constants[eHWSC_Pixel][PS_DIFFUSE_COL][3] = col[3];

  rd->m_RP.m_pShaderResources = &Res;

  // Use optimized shafts
  if( bUseOptBeams )
  {    
    // Setup Shafts render-target
    int nWidth = pShaftsRT->GetWidth();
    int nHeight = pShaftsRT->GetHeight();

    rd->FX_PushRenderTarget(0, pShaftsRT, &gcpRendD3D->m_DepthBufferOrig);
    rd->RT_SetViewport(0, 0, nWidth, nHeight);      

    if( !( rd->m_RP.m_PersFlags2 & RBPF2_LIGHTSHAFTS ) )
    {
      ColorF clearColor(0, 0, 0, 0);
      gcpRendD3D->EF_ClearBuffers(FRT_CLEAR_COLOR, &clearColor);    
    }
  }

  rd->m_RP.m_FlagsShader_RT = 0;

  if (pLight && (pLight->m_Flags & DLF_CASTSHADOW_MAPS) && pLight->m_pShadowMapFrustums && pLight->m_pShadowMapFrustums[0]) 
  {   
    pFr = pLight->m_pShadowMapFrustums[0];
    if(pFr)
    {      
      rd->SetupShadowOnlyPass(0, pLight->m_pShadowMapFrustums[0], (rd->m_RP.m_ObjFlags & FOB_TRANS_MASK) ? &rd->m_RP.m_pCurObject->m_II.m_Matrix : NULL); 
      //reset bias param for first sampler
      rd->m_cEF.m_TempVecs[1][0] = 0.0f;  


      rd->m_RP.m_FlagsShader_RT &= ~( g_HWSR_MaskBit[HWSR_SAMPLE0] | g_HWSR_MaskBit[HWSR_SAMPLE1] | g_HWSR_MaskBit[HWSR_SAMPLE2] | g_HWSR_MaskBit[HWSR_SAMPLE3] | g_HWSR_MaskBit[HWSR_CUBEMAP0] |
                                      g_HWSR_MaskBit[HWSR_POINT_LIGHT] | g_HWSR_MaskBit[HWSR_HW_PCF_COMPARE]);

      rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];

      if (!(pFr->m_Flags & DLF_DIRECTIONAL))
      {
        rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[ HWSR_POINT_LIGHT ];  
      }

      if (pFr->bHWPCFCompare)
      {
        rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[ HWSR_HW_PCF_COMPARE ];
        //reset fOneDivFarDist param for first sampler
        //rd->m_cEF.m_TempVecs[2][0] = 1.f;
      }
      else 
      {
        rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SHADOW_MIXED_MAP_G16R16]; 
      }

    }
  }
  rd->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_OBJ_IDENTITY];

  if (CRenderer::CV_r_beamshelpers)
  {
    rd->FX_SetState(GS_DEPTHWRITE | GS_WIREFRAME);
    CTexture::s_ptexWhite->Apply(0);
    CTexture::s_ptexWhite->Apply(1);

    SAuxGeomRenderFlags auxFlags;
    auxFlags.SetFillMode(e_FillModeWireframe);
    auxFlags.SetDepthTestFlag(e_DepthTestOff);
    rd->GetIRenderAuxGeom()->SetRenderFlags(auxFlags);

    ColorB cR = Col_Yellow;
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[0], cR, vPoints[4], cR, vPoints[7], cR);
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[0], cR, vPoints[7], cR, vPoints[3], cR);

    ColorB cT = Col_Yellow;
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[1], cT, vPoints[5], cT, vPoints[4], cT);
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[1], cT, vPoints[4], cT, vPoints[0], cT);

    ColorB cL = Col_Yellow;
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[2], cL, vPoints[6], cL, vPoints[5], cL);
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[2], cL, vPoints[5], cL, vPoints[1], cL);

    ColorB cB = Col_Yellow;
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[2], cB, vPoints[3], cB, vPoints[7], cB);
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[2], cB, vPoints[7], cB, vPoints[6], cB);

    ColorB cN = Col_Yellow;
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[2], cN, vPoints[1], cL, vPoints[0], cN);
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[2], cN, vPoints[0], cL, vPoints[3], cN);

    ColorB cF = Col_Yellow;
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[2], cF, vPoints[1], cF, vPoints[0], cF);
    rd->GetIRenderAuxGeom()->DrawTriangle(vPoints[2], cF, vPoints[0], cF, vPoints[3], cF);
  }
  else
  {
    if( bUseOptBeams )
    {
      // make sure not to use depth test in optimized beams
      sl->m_RenderState |= GS_NODEPTHTEST;           
    }
    else
    {
      sl->m_RenderState &= ~GS_NODEPTHTEST;
    }

    
    // to save a little bit fillrate (not much..)
    sl->m_RenderState |= GS_ALPHATEST_GREATER;              
    sl->m_AlphaRef = 0;

    rd->FX_CommitStates(pTech, sl, false);
  }

  curPS->mfSet(HWSF_SETTEXTURES);
  curPS->mfSetParametersPI(NULL, NULL);

  curVS->mfSet(0);
  curVS->mfSetParametersPI(NULL, ef);

#if !defined(XENON) && !defined(PS3) && !defined(CAFE)
  CHWShader_D3D::mfBindGS(NULL, NULL);
#endif

  TArray<Vec3> vP;
  TArray<uint16> vI;
  float fDots[32];
  Plane p = pNear;
  
  int nCount( 0 );

  // update nearest current distance (to save some useless computations)
  //fCurDist = rcam.Near - (p.n.x * rcam.Orig.x +  p.n.y * rcam.Orig.y + p.n.z * rcam.Orig.z);

  while (fCurDist < fEndDist)
  {    
    p.d = fCurDist;
    float fFar = p.DistFromPlane(rcam.Orig);
    if (fFar > rcam.Near)
    {
      // Clip current slice by light frustum
      int nOffsV = vP.Num();

      // Define original full-screen polygon
      float FarZ = -fFar + 0.5f, FN = fFar/rcam.Near + 0.5f;     
      float fwL=rcam.wL*FN, fwR=rcam.wR*FN, fwB=rcam.wB*FN, fwT=rcam.wT*FN;
      
      Vec3* vNew = vP.AddIndex(4);
      vNew[0] = Vec3(fwR,fwT,FarZ);
      vNew[1] = Vec3(fwL,fwT,FarZ);
      vNew[2] = Vec3(fwL,fwB,FarZ);
      vNew[3] = Vec3(fwR,fwB,FarZ);

      for ( int j(0); j < 4; ++j )
      {
        vP[j+nOffsV] = rcam.CamToWorld(vP[j+nOffsV]); 
      }

      // Clip polygon by light frustum planes
      if (CRenderer::CV_r_beamssoftclip == 1)
      {
        for(int nPlaneIndex=0; nPlaneIndex<6; nPlaneIndex++)
        {
          uint32 nVertexIndex;
          for(nVertexIndex=0; nVertexIndex<vP.Num()-nOffsV; nVertexIndex++)
          {
            fDots[nVertexIndex] = clipPlanes[nPlaneIndex].DistFromPlane(vP[nVertexIndex+nOffsV]) - ( (nPlaneIndex==4)? pLight->m_fProjectorNearPlane:0);
          }
          uint32  nPrevVertexIndex = vP.Num() - nOffsV - 1;
          for(nVertexIndex=0; nVertexIndex<vP.Num()-nOffsV; nVertexIndex++)
          {
            float fDot = fDots[nVertexIndex];
            float fPrevDot = fDots[nPrevVertexIndex];

            // sign change, this plane clips this polys's edge
            if(fDot*fPrevDot < 0.0f)
            {
              Vec3 vPrevVertex = vP[nPrevVertexIndex+nOffsV];
              Vec3 vVertex = vP[nVertexIndex+nOffsV];

              float fFrac = - fPrevDot / (fDot - fPrevDot);     
               // add new vertex
              Vec3& v = vP.Insert(nVertexIndex+nOffsV);
              v = vPrevVertex + (vVertex - vPrevVertex) * fFrac;  

              // add new dot
              memmove(&fDots[nVertexIndex+1], &fDots[nVertexIndex], (vP.Num()-nOffsV-1-nVertexIndex)*sizeof(float));
              fDots[nVertexIndex] = 0.0f;
              nVertexIndex++;
            }

            nPrevVertexIndex = nVertexIndex;
          }

          // Remove clipped away vertices.
          int nDotVertexIndex = nOffsV;
          int nDots = vP.Num()-nOffsV;
          for(int nDotIndex=0; nDotIndex<nDots; nDotIndex++)
          {
            if(fDots[nDotIndex] < 0.0f)
            {
              vP.Remove(nDotVertexIndex);
            }
            else
              nDotVertexIndex++;
          }  
        }
      }
      // If we still have the polygon after clipping add this to the list
      int nVerts = vP.Num()-nOffsV;
      if (nVerts >= 3) 
      {
        for (i=0; i<nVerts-2; i++)
        {
          vI.AddElem(nOffsV);
          vI.AddElem(i+nOffsV+1);
          vI.AddElem(i+nOffsV+2);
        }
        
        nCount++; 

        // just in case..
        if( nCount > (float)CRenderer::CV_r_beamsmaxslices )
          break;
      }
    }

    fCurDist += fIncrDist;    
  }

  if (vI.Num() >= 3)
  {
    uint32 nOffs, nIOffs;
    SVF_P3F_C4B_T2F *vDst = (SVF_P3F_C4B_T2F *)rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].LockVB(vP.Num(), nOffs);
    uint16 *iDst = rd->m_DynIB.LockIB(vI.Num(), nIOffs);

    for (i=0; i<(int)vP.Num(); i++)
    {
      vDst[i].xyz = vP[i];
    }
    memcpy(iDst, &vI[0], vI.Num()*sizeof(uint16));

    rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].UnlockVB();
    rd->m_DynIB.UnlockIB();

    // Set culling mode
    if (!(rd->m_RP.m_FlagsPerFlush & RBSI_LOCKCULL))
    {
      if (sl->m_eCull != -1)
        rd->D3DSetCull((ECull)sl->m_eCull);
    }

    if (!FAILED(rd->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
    {
      HRESULT h = rd->m_DynVB[POOL_P3F_COL4UB_TEX2F].Bind();
      h = rd->m_DynIB.Bind();
      rd->FX_Commit();
			rd->FX_DrawIndexedPrimitive(eptTriangleList, nOffs, 0, vP.Num(), nIOffs, vI.Num());
    }
  }
  else
  {
    rd->FX_Commit();  
  }

  rd->m_RP.m_pCurObject = pObj;
  rd->m_RP.m_pShaderResources = pRes;

  if (!CRenderer::CV_r_beamssoftclip)
  {
    /*if (rd->m_RP.m_ClipPlaneEnabled == 2)
    {
      Plane pl;
      pl.n = rd->m_RP.m_CurClipPlane.m_Normal;
      pl.d = rd->m_RP.m_CurClipPlane.m_Dist;
      Plane plTr = TransformPlane2(rd->m_InvCameraProjMatrix, pl);
#if defined (DIRECT3D9)
      rd->m_pd3dDevice->SetClipPlane(0, &plTr.n[0]);
      rd->m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0x1);
#elif defined (DIRECT3D10)
      assert(0);
#endif
    }
    else
    {
#if defined (DIRECT3D9)
      rd->m_pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
#elif defined (DIRECT3D10)
      assert(0);
#endif
    }*/
  }


  if( bUseOptBeams )
  {
    rd->FX_PopRenderTarget(0);          
    rd->RT_SetViewport(vX, vY, vWidth, vHeight); 

    // Activate glow effect    
    if( !CRenderer::CV_r_HDRRendering)
    {
      CEffectParam *pParam = PostEffectMgr()->GetByName("Glow_Active"); 
      assert(pParam && "Parameter doesn't exist");
      pParam->SetParam(1.0f);   
    }
    
    gcpRendD3D->FX_Commit();

    rd->m_RP.m_PersFlags2 |= RBPF2_LIGHTSHAFTS;
  }

  rd->m_RP.m_FlagsShader_RT = nCurrFlagShader_RT;
  rd->m_RP.m_PrevLMask = -1;
	rd->m_RP.m_nCommitFlags = currCommitFlags;

  return true;
} 

bool CREParticle::mfPreDraw(SShaderPass *sl)
{
	CD3D9Renderer* rd(gcpRendD3D);
	SRenderPipeline& rp(rd->m_RP);

	bool bGeomShader = rp.m_pCurTechnique && (rp.m_pCurTechnique->m_Flags & FHF_USE_GEOMETRY_SHADER);
	if (rp.m_RendNumVerts && (bGeomShader || rp.m_RendNumIndices))
	{		
		if( rp.m_FlagsPerFlush & RBSI_EXTERN_VMEM_BUFFERS )
		{			
			assert(rp.m_pExternalVertexBuffer);
			assert(rp.m_pExternalIndexBuffer);

			// bind out external vertex/index buffer to use those directly, the client code has to set them up correctly
			rp.m_pExternalVertexBuffer->Bind(0, 0, rp.m_StreamStride);
			rp.m_pExternalIndexBuffer->Bind();

			// adjust the first index to render from as well as 
			// other renderer stats
			rp.m_nStreamOffset[0] = 0;
			rp.m_FirstIndex = rp.m_nExternalVertexBufferFirstIndex;	
			rp.m_FirstVertex = rp.m_nExternalVertexBufferFirstVertex;	

			rp.m_PS[rp.m_nProcessThreadID].m_DynMeshUpdateBytes += rp.m_StreamStride*rp.m_RendNumVerts;
			rp.m_PS[rp.m_nProcessThreadID].m_DynMeshUpdateBytes += rp.m_RendNumIndices*sizeof(short);

			// clear external video memory buffer flag
			rp.m_FlagsPerFlush &= ~RBSI_EXTERN_VMEM_BUFFERS;
			rp.m_nExternalVertexBufferFirstIndex = 0;
			rp.m_nExternalVertexBufferFirstVertex = 0;
			rp.m_pExternalVertexBuffer = NULL;
			rp.m_pExternalIndexBuffer = NULL;
		}
		else
		{
			uint32 nStart;
			uint32 nSize = rp.m_StreamStride * rp.m_RendNumVerts;
			if (!(rp.m_FlagsPerFlush & RBSI_VERTSMERGED))
			{
				rp.m_FlagsPerFlush |= RBSI_VERTSMERGED;
				void *pVB = rd->FX_LockVB(nSize, nStart);
#ifndef XENON
				memcpy(pVB, rp.m_StreamPtr.Ptr, nSize);


#endif
				rd->FX_UnlockVB();
				rp.m_FirstVertex = 0;
				rp.m_nStreamOffset[0] = nStart;
				rp.m_PS[rd->m_RP.m_nProcessThreadID].m_DynMeshUpdateBytes += nSize;
#if defined(DIRECT3D10)
				assert(!bGeomShader && rp.m_RendNumIndices || bGeomShader && !rp.m_RendNumIndices);
				if (rp.m_RendNumIndices)
#endif
				{
					uint16 *pIB = rp.m_pIndexBuf->LockIB(rp.m_RendNumIndices, nStart);
#ifndef XENON
					memcpy(pIB, rp.m_SysRendIndices, rp.m_RendNumIndices * sizeof(short));


#endif
					rp.m_pIndexBuf->UnlockIB();
					rp.m_FirstIndex = nStart;
					rp.m_PS[rd->m_RP.m_nProcessThreadID].m_DynMeshUpdateBytes += rp.m_RendNumIndices * sizeof(short);
				}
			}
			rp.m_pVBs->Bind(0, rp.m_nStreamOffset[0], rp.m_StreamStride);		
			rp.m_pIndexBuf->Bind();
		}
	}

	return true;
}

bool CREParticle::mfDraw(CShader *ef, SShaderPass *sl)
{
	CD3D9Renderer* rd(gcpRendD3D);
	SRenderPipeline& rp(rd->m_RP);
	
	rd->FX_Commit();

	bool bGeomShader = false;
#if defined (DIRECT3D10)
	bGeomShader = rp.m_pCurTechnique && (rp.m_pCurTechnique->m_Flags & FHF_USE_GEOMETRY_SHADER);
	if (bGeomShader && (!CHWShader_D3D::m_pCurInstGS || CHWShader_D3D::m_pCurInstGS->m_bFallback))
		return false;
	if (!CHWShader_D3D::m_pCurInstVS || CHWShader_D3D::m_pCurInstVS->m_bFallback)
		return false;
	if (!CHWShader_D3D::m_pCurInstPS || CHWShader_D3D::m_pCurInstPS->m_bFallback)
		return false;
#endif

	if(bGeomShader)
		rd->FX_DrawPrimitive(eptPointList, rp.m_FirstVertex, rp.m_RendNumVerts);
	else
		rd->FX_DrawIndexedPrimitive(eptTriangleList, 0, rp.m_FirstVertex, rp.m_RendNumVerts, rp.m_FirstIndex + rp.m_IndexOffset, rd->m_RP.m_RendNumIndices);

	return true;
}

bool CRELightPropagationVolume::mfDraw(CShader* ef, SShaderPass* sfm)
{
	static ICVar *pGI = iConsole->GetCVar("e_gi");
	if(pGI->GetIVal() != 0)
		Evaluate();
	return true;
}

bool CREGameEffect::mfDraw(CShader* ef, SShaderPass* sfm)
{
	CRY_ASSERT_MESSAGE(gRenDev->m_pRT->IsRenderThread(),"Trying to render from wrong thread");
	CRY_ASSERT(ef);
	CRY_ASSERT(sfm);

	if(m_pImpl)
	{
#ifndef _RELEASE
		IMaterial* pMaterial = (gRenDev->m_RP.m_pCurObject) ? (gRenDev->m_RP.m_pCurObject->m_pCurrMaterial) : NULL;
		const char* pEffectName = (pMaterial) ? (PathUtil::GetFileName(pMaterial->GetName())) : "GameEffectRenderElement";
		PROFILE_LABEL_PUSH( pEffectName );
#endif

		uint32 passCount	= 0;
		bool successFlag	= true;

		// Begin drawing
		ef->FXBegin(&passCount, 0);
		if(passCount > 0)
		{
			// Begin pass
			ef->FXBeginPass(0);

			// Draw element
			successFlag = m_pImpl->mfDraw(ef,sfm,gRenDev->m_RP.m_pCurObject);

			// End pass
			ef->FXEndPass();
		}
		// End drawing
		ef->FXEnd();

#ifndef _RELEASE
		PROFILE_LABEL_POP( pEffectName );
#endif

		return successFlag;
	}
	return false;
}
